liquid_feedback_frontend
annotate app/main/timeline/index.lua @ 146:77260f05fd4b
implement advanced date searches
date-date in range
since: date
age: 10 timestamp
date-date in range
since: date
age: 10 timestamp
| author | Daniel Poelzleithner <poelzi@poelzi.org> | 
|---|---|
| date | Thu Oct 07 03:34:19 2010 +0200 (2010-10-07) | 
| parents | 90520c9fca44 | 
| children | 165f4bd02cf3 | 
| rev | line source | 
|---|---|
| bsw@11 | 1 execute.view{ | 
| bsw@11 | 2 module = "timeline", | 
| bsw@11 | 3 view = "_constants" | 
| bsw@11 | 4 } | 
| bsw@11 | 5 | 
| poelzi@144 | 6 local active_name = "" | 
| poelzi@145 | 7 local areas_ignored = {} | 
| bsw@11 | 8 local options_box_count = param.get("options_box_count", atom.number) or 1 | 
| bsw@11 | 9 if options_box_count > 10 then | 
| bsw@11 | 10 options_box_count = 10 | 
| bsw@11 | 11 end | 
| bsw@10 | 12 | 
| bsw@10 | 13 local function format_dow(dow) | 
| bsw@10 | 14 local dows = { | 
| bsw@10 | 15 _"Monday", | 
| bsw@10 | 16 _"Tuesday", | 
| bsw@10 | 17 _"Wednesday", | 
| bsw@10 | 18 _"Thursday", | 
| bsw@10 | 19 _"Friday", | 
| bsw@10 | 20 _"Saturday", | 
| bsw@10 | 21 _"Sunday" | 
| bsw@10 | 22 } | 
| bsw@10 | 23 return dows[dow+1] | 
| bsw@10 | 24 end | 
| bsw@11 | 25 slot.put_into("title", _"Timeline") | 
| bsw@10 | 26 | 
| bsw@11 | 27 slot.select("actions", function() | 
| bsw@11 | 28 local setting_key = "liquidfeedback_frontend_timeline_current_options" | 
| bsw@11 | 29 local setting = Setting:by_pk(app.session.member.id, setting_key) | 
| bsw@11 | 30 local current_options = "" | 
| bsw@11 | 31 if setting then | 
| bsw@11 | 32 current_options = setting.value | 
| bsw@11 | 33 end | 
| bsw@11 | 34 local setting_maps = app.session.member:get_setting_maps_by_key("timeline_filters") | 
| bsw@11 | 35 for i, setting_map in ipairs(setting_maps) do | 
| bsw@11 | 36 local active | 
| bsw@11 | 37 local options_string = setting_map.value | 
| bsw@11 | 38 local name = setting_map.subkey | 
| bsw@11 | 39 if options_string == current_options then | 
| bsw@11 | 40 active = true | 
| poelzi@144 | 41 active_name = name | 
| bsw@11 | 42 end | 
| bsw@11 | 43 ui.link{ | 
| bsw/jbe@19 | 44 image = { static = "icons/16/time.png" }, | 
| bsw/jbe@19 | 45 attr = { class = active and "action_active" or nil }, | 
| bsw/jbe@19 | 46 text = name, | 
| poelzi@145 | 47 form_attr = { class = "inline" }, | 
| bsw@11 | 48 module = 'timeline', | 
| bsw@11 | 49 action = 'update', | 
| bsw@11 | 50 params = { | 
| bsw@11 | 51 options_string = options_string | 
| bsw@11 | 52 }, | 
| bsw@11 | 53 } | 
| bsw@11 | 54 end | 
| bsw@11 | 55 if #setting_maps > 0 then | 
| bsw@11 | 56 ui.link{ | 
| bsw@11 | 57 content = function() | 
| bsw@11 | 58 ui.image{ static = "icons/16/wrench.png" } | 
| bsw@11 | 59 slot.put(_"Manage filter") | 
| bsw@11 | 60 end, | 
| bsw@11 | 61 module = "timeline", | 
| bsw@11 | 62 view = "list_filter", | 
| bsw@11 | 63 } | 
| bsw@11 | 64 end | 
| bsw@11 | 65 ui.link{ | 
| bsw@11 | 66 content = function() | 
| bsw@11 | 67 ui.image{ static = "icons/16/bullet_disk.png" } | 
| bsw@11 | 68 slot.put(_"Save current filter") | 
| bsw@11 | 69 end, | 
| bsw@11 | 70 module = "timeline", | 
| bsw@11 | 71 view = "save_filter", | 
| poelzi@144 | 72 params = { | 
| poelzi@144 | 73 current_name = active_name | 
| poelzi@144 | 74 }, | 
| bsw@11 | 75 attr = { | 
| bsw@11 | 76 onclick = "el=document.getElementById('timeline_save');el.checked=true;el.form.submit();return(false);" | 
| bsw@11 | 77 } | 
| bsw@11 | 78 } | 
| bsw@11 | 79 end) | 
| bsw@10 | 80 | 
| bsw@11 | 81 util.help("timeline.index", _"Timeline") | 
| bsw@10 | 82 | 
| bsw@10 | 83 ui.form{ | 
| bsw@10 | 84 module = "timeline", | 
| bsw@11 | 85 action = "update", | 
| bsw@10 | 86 content = function() | 
| bsw/jbe@19 | 87 ui.container{ | 
| bsw@11 | 88 | 
| bsw@11 | 89 content = function() | 
| bsw/jbe@19 | 90 | 
| bsw/jbe@19 | 91 ui.tag{ | 
| bsw/jbe@19 | 92 tag = "input", | 
| bsw/jbe@19 | 93 attr = { | 
| bsw/jbe@19 | 94 type = "radio", | 
| bsw/jbe@19 | 95 id = "timeline_search_last_24h", | 
| bsw/jbe@19 | 96 name = "search_from", | 
| bsw/jbe@19 | 97 value = "last_24h", | 
| bsw/jbe@19 | 98 checked = param.get("date") == "last_24h" and "checked" or nil | 
| bsw/jbe@19 | 99 }, | 
| bsw@11 | 100 } | 
| bsw/jbe@19 | 101 | 
| bsw/jbe@19 | 102 ui.tag{ | 
| bsw/jbe@19 | 103 tag = "label", | 
| bsw/jbe@19 | 104 attr = { | 
| bsw/jbe@19 | 105 ["for"] = "timeline_search_last_24h" | 
| bsw/jbe@19 | 106 }, | 
| bsw/jbe@19 | 107 content = " " .. _"last 24 hours" .. " " | 
| bsw/jbe@19 | 108 } | 
| bsw/jbe@19 | 109 | 
| bsw/jbe@19 | 110 ui.tag{ | 
| bsw/jbe@19 | 111 tag = "input", | 
| bsw/jbe@19 | 112 attr = { | 
| bsw/jbe@19 | 113 type = "radio", | 
| bsw/jbe@19 | 114 id = "timeline_search_from_date", | 
| bsw/jbe@19 | 115 name = "search_from", | 
| bsw/jbe@19 | 116 value = "date", | 
| bsw/jbe@19 | 117 checked = not (param.get("date") == "last_24h") and "checked" or nil | 
| bsw/jbe@19 | 118 }, | 
| bsw@11 | 119 } | 
| bsw@11 | 120 | 
| bsw/jbe@19 | 121 slot.put(" ") | 
| bsw/jbe@19 | 122 local current_date = param.get("date") | 
| bsw/jbe@19 | 123 if not current_date or #current_date == 0 or current_date == "last_24h" then | 
| bsw/jbe@19 | 124 current_date = tostring(db:query("select now()::date as date")[1].date) | 
| bsw/jbe@19 | 125 end | 
| bsw/jbe@19 | 126 ui.tag{ | 
| bsw/jbe@19 | 127 tag = "input", | 
| bsw/jbe@19 | 128 attr = { | 
| bsw/jbe@19 | 129 type = "text", | 
| bsw/jbe@19 | 130 id = "timeline_search_date", | 
| bsw/jbe@19 | 131 style = "width: 10em;", | 
| bsw/jbe@19 | 132 onchange = "this.form.submit();", | 
| bsw/jbe@19 | 133 onclick = "document.getElementById('timeline_search_from_date').checked = true;", | 
| bsw/jbe@19 | 134 name = "date", | 
| bsw/jbe@19 | 135 value = current_date | 
| bsw/jbe@19 | 136 }, | 
| bsw/jbe@19 | 137 content = function() end | 
| bsw/jbe@19 | 138 } | 
| bsw/jbe@19 | 139 | 
| bsw/jbe@19 | 140 ui.script{ static = "gregor.js/gregor.js" } | 
| poelzi@146 | 141 util.gregor("timeline_search_date", true) | 
| bsw/jbe@19 | 142 | 
| bsw/jbe@19 | 143 | 
| bsw/jbe@19 | 144 ui.link{ | 
| bsw/jbe@19 | 145 attr = { style = "margin-left: 1em; font-weight: bold;", onclick = "document.getElementById('timeline_search_date').form.submit();return(false);" }, | 
| bsw/jbe@19 | 146 content = function() | 
| bsw/jbe@19 | 147 ui.image{ | 
| bsw/jbe@19 | 148 attr = { style = "margin-right: 0.25em;" }, | 
| bsw/jbe@19 | 149 static = "icons/16/magnifier.png" | 
| bsw/jbe@19 | 150 } | 
| bsw/jbe@19 | 151 slot.put(_"Search") | 
| bsw/jbe@19 | 152 end, | 
| bsw/jbe@19 | 153 external = "#", | 
| bsw/jbe@19 | 154 } | 
| bsw/jbe@19 | 155 local show_options = param.get("show_options", atom.boolean) | 
| bsw/jbe@19 | 156 ui.link{ | 
| bsw/jbe@19 | 157 attr = { style = "margin-left: 1em;", onclick = "el=document.getElementById('timeline_show_options');el.checked=" .. tostring(not show_options) .. ";el.form.submit();return(false);" }, | 
| bsw/jbe@19 | 158 content = function() | 
| bsw/jbe@19 | 159 ui.image{ | 
| bsw/jbe@19 | 160 attr = { style = "margin-right: 0.25em;" }, | 
| bsw/jbe@19 | 161 static = "icons/16/text_list_bullets.png" | 
| bsw/jbe@19 | 162 } | 
| bsw/jbe@19 | 163 slot.put(not show_options and _"Show filter details" or _"Hide filter details") | 
| bsw/jbe@19 | 164 end, | 
| bsw/jbe@19 | 165 external = "#", | 
| bsw/jbe@19 | 166 } | 
| bsw@11 | 167 | 
| bsw/jbe@19 | 168 ui.field.boolean{ | 
| bsw/jbe@19 | 169 attr = { id = "timeline_show_options", style = "display: none;", onchange="this.form.submit();" }, | 
| bsw/jbe@19 | 170 name = "show_options", | 
| bsw/jbe@19 | 171 value = param.get("show_options", atom.boolean) | 
| bsw/jbe@19 | 172 } | 
| poelzi@144 | 173 ui.hidden_field{ name = "current_name", value = active_name } | 
| bsw/jbe@19 | 174 ui.field.boolean{ | 
| bsw/jbe@19 | 175 attr = { id = "timeline_save", style = "display: none;", onchange="this.form.submit();" }, | 
| bsw/jbe@19 | 176 name = "save", | 
| bsw/jbe@19 | 177 value = false | 
| bsw/jbe@19 | 178 } | 
| bsw/jbe@19 | 179 | 
| bsw/jbe@19 | 180 end | 
| bsw@10 | 181 } | 
| bsw@11 | 182 | 
| bsw@11 | 183 ui.container{ | 
| bsw@11 | 184 attr = { | 
| bsw@11 | 185 id = "timeline_options_boxes", | 
| bsw@11 | 186 class = "vertical", | 
| bsw@11 | 187 style = not param.get("show_options", atom.boolean) and "display: none;" or nil | 
| bsw@10 | 188 }, | 
| bsw@11 | 189 content = function() | 
| bsw@11 | 190 | 
| bsw@11 | 191 local function option_field(event_ident, filter_ident) | 
| bsw@11 | 192 local param_name | 
| bsw@11 | 193 if not filter_ident then | 
| bsw@11 | 194 param_name = "option_" .. event_ident | 
| bsw@11 | 195 else | 
| bsw@11 | 196 param_name = "option_" .. event_ident .. "_" .. filter_ident | 
| bsw@11 | 197 end | 
| bsw@11 | 198 local value = param.get(param_name, atom.boolean) | 
| bsw@11 | 199 ui.field.boolean{ | 
| bsw@11 | 200 attr = { id = param_name }, | 
| bsw@11 | 201 name = param_name, | 
| bsw@11 | 202 value = value, | 
| bsw@11 | 203 } | 
| bsw@11 | 204 end | 
| bsw@11 | 205 | 
| bsw@11 | 206 local function filter_option_fields(event_ident, filter_idents) | 
| bsw@11 | 207 | 
| bsw@11 | 208 for i, filter_ident in ipairs(filter_idents) do | 
| bsw@11 | 209 slot.put("<td>") | 
| bsw@11 | 210 option_field(event_ident, filter_ident) | 
| bsw@11 | 211 slot.put("</td><td><div class='ui_field_label label_right'>") | 
| bsw@11 | 212 ui.tag{ | 
| bsw@11 | 213 attr = { ["for"] = "option_" .. event_ident .. "_" .. filter_ident }, | 
| bsw@11 | 214 tag = "label", | 
| bsw@11 | 215 content = filter_names[filter_ident] | 
| bsw@11 | 216 } | 
| bsw@11 | 217 slot.put("</div></td>") | 
| bsw@11 | 218 end | 
| bsw@11 | 219 | 
| bsw@11 | 220 end | 
| bsw@10 | 221 | 
| bsw@11 | 222 local event_groups = { | 
| bsw@11 | 223 { | 
| bsw@11 | 224 title = _"Issue events", | 
| bsw@11 | 225 event_idents = { | 
| bsw@11 | 226 "issue_created", | 
| bsw@11 | 227 "issue_canceled", | 
| bsw@11 | 228 "issue_accepted", | 
| bsw@11 | 229 "issue_half_frozen", | 
| bsw@11 | 230 "issue_finished_without_voting", | 
| bsw@11 | 231 "issue_voting_started", | 
| bsw@11 | 232 "issue_finished_after_voting", | 
| bsw@11 | 233 }, | 
| bsw@11 | 234 filter_idents = { | 
| bsw@11 | 235 "membership", | 
| bsw@11 | 236 "interested" | 
| bsw@11 | 237 } | 
| bsw@11 | 238 }, | 
| bsw@11 | 239 { | 
| bsw@11 | 240 title = _"Initiative events", | 
| bsw@11 | 241 event_idents = { | 
| bsw@11 | 242 "initiative_created", | 
| bsw@11 | 243 "initiative_revoked", | 
| bsw@11 | 244 "draft_created", | 
| bsw@11 | 245 "suggestion_created", | 
| bsw@11 | 246 }, | 
| bsw@11 | 247 filter_idents = { | 
| bsw@11 | 248 "membership", | 
| bsw@11 | 249 "interested", | 
| bsw@11 | 250 "supporter", | 
| bsw@11 | 251 "potential_supporter", | 
| bsw@11 | 252 "initiator" | 
| bsw@11 | 253 } | 
| bsw@11 | 254 } | 
| bsw@11 | 255 } | 
| bsw@11 | 256 | 
| bsw@11 | 257 slot.put("<table>") | 
| bsw@11 | 258 | 
| bsw@11 | 259 for i_event_group, event_group in ipairs(event_groups) do | 
| bsw@11 | 260 slot.put("<tr>") | 
| bsw@11 | 261 slot.put("<th colspan='2'>") | 
| bsw@11 | 262 slot.put(event_group.title) | 
| bsw@11 | 263 slot.put("</th><th colspan='10'>") | 
| bsw@11 | 264 slot.put(_"Show only events which match... (or associtated)") | 
| bsw@11 | 265 slot.put("</th>") | 
| bsw@11 | 266 slot.put("</tr>") | 
| bsw@11 | 267 local event_idents = event_group.event_idents | 
| bsw@11 | 268 for i, event_ident in ipairs(event_idents) do | 
| bsw@11 | 269 slot.put("<tr><td>") | 
| bsw@11 | 270 option_field(event_ident) | 
| bsw@11 | 271 slot.put("</td><td><div class='ui_field_label label_right'>") | 
| bsw@11 | 272 ui.tag{ | 
| bsw@11 | 273 attr = { ["for"] = "option_" .. event_ident }, | 
| bsw@11 | 274 tag = "label", | 
| bsw@11 | 275 content = event_names[event_ident] | 
| bsw@11 | 276 } | 
| bsw@11 | 277 slot.put("</div></td>") | 
| bsw@11 | 278 filter_option_fields(event_ident, event_group.filter_idents) | 
| bsw@11 | 279 slot.put("</tr>") | 
| bsw@11 | 280 end | 
| bsw@11 | 281 end | 
| bsw@11 | 282 | 
| bsw@11 | 283 slot.put("</table>") | 
| bsw@11 | 284 | 
| poelzi@145 | 285 local areas = Area:new_selector():add_where("active='t'"):exec() | 
| poelzi@145 | 286 for i, area in ipairs(areas) do | 
| poelzi@145 | 287 if param.get("option_ignore_area_"..tostring(area.id)) then | 
| poelzi@145 | 288 areas_ignored[#areas_ignored+1] = area.id | 
| poelzi@145 | 289 end | 
| poelzi@145 | 290 end | 
| poelzi@145 | 291 | 
| poelzi@145 | 292 ui.multiselect{ | 
| poelzi@145 | 293 style = "checkbox", | 
| poelzi@145 | 294 selected_ids = areas_ignored, | 
| poelzi@145 | 295 container_attr = { class = "ignore_area_list" }, | 
| poelzi@145 | 296 container2_attr = { class = "ignore_area_item" }, | 
| poelzi@145 | 297 label = _"Ignore Areas", | 
| poelzi@145 | 298 name = "option_ignore_area[]", | 
| poelzi@145 | 299 foreign_records = areas, | 
| poelzi@145 | 300 foreign_id = "id", | 
| poelzi@145 | 301 foreign_name = "name" | 
| poelzi@145 | 302 } | 
| poelzi@145 | 303 | 
| bsw@11 | 304 end | 
| bsw@10 | 305 } | 
| bsw@10 | 306 end | 
| bsw@10 | 307 } | 
| bsw@10 | 308 | 
| bsw@10 | 309 local date = param.get("date") | 
| bsw/jbe@19 | 310 | 
| bsw@11 | 311 if not date or #date == 0 then | 
| bsw@10 | 312 date = "today" | 
| bsw@10 | 313 end | 
| bsw@11 | 314 | 
| bsw@11 | 315 local timeline_selector | 
| bsw@11 | 316 | 
| bsw@11 | 317 for event, event_name in pairs(event_names) do | 
| bsw@11 | 318 | 
| bsw@11 | 319 if param.get("option_" .. event, atom.boolean) then | 
| bsw@11 | 320 | 
| bsw@11 | 321 local tmp = Timeline:new_selector() | 
| bsw/jbe@19 | 322 if event == "draft_created" then | 
| bsw/jbe@19 | 323 tmp | 
| bsw/jbe@19 | 324 :reset_fields() | 
| bsw/jbe@19 | 325 :add_field("max(timeline.occurrence)", "occurrence") | 
| bsw/jbe@19 | 326 :add_field("timeline.event", nil, { "grouped" }) | 
| bsw/jbe@19 | 327 :add_field("timeline.issue_id", nil, { "grouped" }) | 
| bsw@41 | 328 :add_field("draft.initiative_id", nil, { "grouped" }) | 
| bsw/jbe@19 | 329 :add_field("max(timeline.draft_id)", "draft_id") | 
| bsw/jbe@19 | 330 :add_field("timeline.suggestion_id", nil, { "grouped" }) | 
| bsw/jbe@19 | 331 :add_field("COUNT(*)", "count") | 
| bsw/jbe@19 | 332 else | 
| bsw/jbe@19 | 333 tmp | 
| bsw/jbe@19 | 334 :add_field("1", "count") | 
| bsw/jbe@19 | 335 end | 
| bsw@11 | 336 | 
| bsw/jbe@19 | 337 if date == "last_24h" then | 
| bsw/jbe@19 | 338 tmp:add_where{ "occurrence > now() - '24 hours'::interval" } | 
| bsw/jbe@19 | 339 else | 
| poelzi@146 | 340 local start,stop = string.gmatch(date, "(%d+-%d+-%d+):(%d+-%d+-%d+)")() | 
| poelzi@146 | 341 if start and stop then | 
| poelzi@146 | 342 tmp:add_where{ "occurrence::date >= ?::date AND occurrence::date <= ?::date", start, stop } | 
| poelzi@146 | 343 else | 
| poelzi@146 | 344 local age = string.gmatch(date, "age:(.+)")() | 
| poelzi@146 | 345 if age then | 
| poelzi@146 | 346 tmp:add_where{ "occurrence >= now() - ?::interval", age } | 
| poelzi@146 | 347 else | 
| poelzi@146 | 348 local since = string.gmatch(date, "since:%s*(%d+-%d+-%d+)%s*")() | 
| poelzi@146 | 349 if since then | 
| poelzi@146 | 350 tmp:add_where{ "occurrence::date >= ?::date", since } | 
| poelzi@146 | 351 else | 
| poelzi@146 | 352 tmp:add_where{ "occurrence::date = ?::date", date } | 
| poelzi@146 | 353 end | 
| poelzi@146 | 354 end | 
| poelzi@146 | 355 end | 
| bsw/jbe@19 | 356 end | 
| bsw/jbe@19 | 357 tmp | 
| bsw/jbe@19 | 358 :left_join("draft", nil, "draft.id = timeline.draft_id") | 
| bsw/jbe@19 | 359 :left_join("suggestion", nil, "suggestion.id = timeline.suggestion_id") | 
| bsw/jbe@19 | 360 :left_join("initiative", nil, "initiative.id = timeline.initiative_id or initiative.id = draft.initiative_id or initiative.id = suggestion.initiative_id") | 
| bsw/jbe@19 | 361 :left_join("issue", nil, "issue.id = timeline.issue_id or issue.id = initiative.issue_id") | 
| bsw/jbe@19 | 362 :left_join("area", nil, "area.id = issue.area_id") | 
| bsw@11 | 363 | 
| bsw/jbe@19 | 364 :left_join("interest", "_interest", { "_interest.issue_id = issue.id AND _interest.member_id = ?", app.session.member.id} ) | 
| bsw/jbe@19 | 365 :left_join("initiator", "_initiator", { "_initiator.initiative_id = initiative.id AND _initiator.member_id = ?", app.session.member.id} ) | 
| bsw/jbe@19 | 366 :left_join("membership", "_membership", { "_membership.area_id = area.id AND _membership.member_id = ?", app.session.member.id} ) | 
| bsw/jbe@19 | 367 :left_join("supporter", "_supporter", { "_supporter.initiative_id = initiative.id AND _supporter.member_id = ?", app.session.member.id} ) | 
| bsw/jbe@19 | 368 | 
| bsw/jbe@19 | 369 local group | 
| bsw/jbe@19 | 370 if event == "draft_created" then | 
| bsw/jbe@19 | 371 group = { "grouped" } | 
| bsw/jbe@19 | 372 end | 
| bsw/jbe@19 | 373 | 
| bsw/jbe@19 | 374 tmp | 
| bsw/jbe@19 | 375 :add_field("(_interest.member_id NOTNULL)", "is_interested", group) | 
| bsw/jbe@19 | 376 :add_field("(_initiator.member_id NOTNULL)", "is_initiator", group) | 
| bsw/jbe@19 | 377 :add_field({"(_supporter.member_id NOTNULL) AND NOT EXISTS(SELECT NULL FROM opinion WHERE opinion.initiative_id = initiative.id AND opinion.member_id = ? AND ((opinion.degree = 2 AND NOT fulfilled) OR (opinion.degree = -2 AND fulfilled)) LIMIT 1)", app.session.member.id }, "is_supporter", group) | 
| bsw/jbe@19 | 378 :add_field({"EXISTS(SELECT NULL FROM opinion WHERE opinion.initiative_id = initiative.id AND opinion.member_id = ? AND ((opinion.degree = 2 AND NOT fulfilled) OR (opinion.degree = -2 AND fulfilled)) LIMIT 1)", app.session.member.id }, "is_potential_supporter", group) | 
| bsw/jbe@19 | 379 -- :left_join("member", nil, "member.id = timeline.member_id", group) | 
| bsw/jbe@19 | 380 | 
| poelzi@145 | 381 if #areas_ignored > 0 then | 
| poelzi@145 | 382 tmp:add_where{"area.id NOT IN ($)", areas_ignored} | 
| poelzi@145 | 383 end | 
| bsw@11 | 384 | 
| bsw@11 | 385 tmp:add_where{ "event = ?", event } | 
| bsw@11 | 386 | 
| bsw@11 | 387 local filters = {} | 
| bsw@11 | 388 if param.get("option_" .. event .. "_membership", atom.boolean) then | 
| bsw@11 | 389 filters[#filters+1] = "(timeline.initiative_id ISNULL AND timeline.issue_id ISNULL AND timeline.draft_id ISNULL AND timeline.suggestion_id ISNULL) OR _membership.member_id NOTNULL" | 
| bsw@11 | 390 end | 
| bsw@11 | 391 | 
| bsw@11 | 392 if param.get("option_" .. event .. "_supporter", atom.boolean) then | 
| bsw@11 | 393 filters[#filters+1] = "(timeline.initiative_id ISNULL AND timeline.issue_id ISNULL AND timeline.draft_id ISNULL AND timeline.suggestion_id ISNULL) OR ((_supporter.member_id NOTNULL) AND NOT EXISTS(SELECT NULL FROM opinion WHERE opinion.initiative_id = initiative.id AND opinion.member_id = ? AND ((opinion.degree = 2 AND NOT fulfilled) OR (opinion.degree = -2 AND fulfilled)) LIMIT 1))" | 
| bsw@11 | 394 end | 
| bsw@11 | 395 | 
| bsw@11 | 396 if param.get("option_" .. event .. "_potential_supporter", atom.boolean) then | 
| bsw@11 | 397 filters[#filters+1] = "(timeline.initiative_id ISNULL AND timeline.issue_id ISNULL AND timeline.draft_id ISNULL AND timeline.suggestion_id ISNULL) OR ((_supporter.member_id NOTNULL) AND EXISTS(SELECT NULL FROM opinion WHERE opinion.initiative_id = initiative.id AND opinion.member_id = ? AND ((opinion.degree = 2 AND NOT fulfilled) OR (opinion.degree = -2 AND fulfilled)) LIMIT 1))" | 
| bsw@11 | 398 end | 
| bsw@10 | 399 | 
| bsw@11 | 400 if param.get("option_" .. event .. "_interested", atom.boolean) then | 
| bsw@11 | 401 filters[#filters+1] = "(timeline.initiative_id ISNULL AND timeline.issue_id ISNULL AND timeline.draft_id ISNULL AND timeline.suggestion_id ISNULL) OR _interest.member_id NOTNULL" | 
| bsw@11 | 402 end | 
| bsw@11 | 403 | 
| bsw@11 | 404 if param.get("option_" .. event .. "_initiator", atom.boolean) then | 
| bsw@11 | 405 filters[#filters+1] = "(timeline.initiative_id ISNULL AND timeline.issue_id ISNULL AND timeline.draft_id ISNULL AND timeline.suggestion_id ISNULL) OR _initiator.member_id NOTNULL" | 
| bsw@11 | 406 end | 
| bsw@11 | 407 | 
| bsw@11 | 408 if #filters > 0 then | 
| bsw@11 | 409 local filter_string = "(" .. table.concat(filters, ") OR (") .. ")" | 
| bsw/jbe@19 | 410 tmp:add_where{ filter_string, app.session.member.id, app.session.member.id } | 
| bsw@11 | 411 end | 
| bsw@11 | 412 | 
| bsw@11 | 413 if not timeline_selector then | 
| bsw@11 | 414 timeline_selector = tmp | 
| bsw@11 | 415 else | 
| bsw@11 | 416 timeline_selector:union_all(tmp) | 
| bsw@11 | 417 end | 
| bsw@11 | 418 end | 
| bsw@11 | 419 end | 
| bsw@11 | 420 | 
| bsw@11 | 421 if timeline_selector then | 
| bsw@11 | 422 | 
| bsw@11 | 423 local initiatives_per_page = param.get("initiatives_per_page", atom.number) | 
| bsw@11 | 424 | 
| bsw@11 | 425 local outer_timeline_selector = db:new_selector() | 
| bsw@11 | 426 outer_timeline_selector._class = Timeline | 
| bsw/jbe@19 | 427 outer_timeline_selector | 
| bsw/jbe@19 | 428 :add_field{ "timeline.*" } | 
| bsw/jbe@19 | 429 :from({"($)", { timeline_selector }}, "timeline" ) | 
| bsw/jbe@19 | 430 :add_order_by("occurrence DESC") | 
| bsw/jbe@19 | 431 | 
| bsw@11 | 432 slot.put("<br />") | 
| bsw@11 | 433 execute.view{ | 
| bsw@11 | 434 module = "timeline", | 
| bsw@11 | 435 view = "_list", | 
| bsw@11 | 436 params = { | 
| bsw@11 | 437 timeline_selector = outer_timeline_selector, | 
| bsw@11 | 438 per_page = param.get("per_page", atom.number), | 
| bsw@11 | 439 event_names = event_names, | 
| bsw@11 | 440 initiatives_per_page = initiatives_per_page | 
| bsw@11 | 441 } | 
| bsw@10 | 442 } | 
| bsw@11 | 443 | 
| bsw@11 | 444 else | 
| bsw@10 | 445 | 
| bsw@11 | 446 slot.put(_"No events selected to list") | 
| bsw@11 | 447 | 
| bsw@11 | 448 end |