liquid_feedback_frontend
diff app/main/initiative/_show.lua @ 725:344e5fdce8c9
Fixed public search, made draft history available again
author | bsw |
---|---|
date | Thu Jun 28 13:52:42 2012 +0200 (2012-06-28) |
parents | |
children | 161cebfc44d4 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/app/main/initiative/_show.lua Thu Jun 28 13:52:42 2012 +0200 1.3 @@ -0,0 +1,525 @@ 1.4 +local initiative = param.get("initiative", "table") 1.5 + 1.6 +local show_as_head = param.get("show_as_head", atom.boolean) 1.7 + 1.8 +initiative:load_everything_for_member_id(app.session.member_id) 1.9 + 1.10 +local issue = initiative.issue 1.11 + 1.12 +-- TODO performance 1.13 +local initiator 1.14 +if app.session.member_id then 1.15 + initiator = Initiator:by_pk(initiative.id, app.session.member.id) 1.16 +end 1.17 + 1.18 +if app.session.member_id then 1.19 + issue:load_everything_for_member_id(app.session.member_id) 1.20 +end 1.21 + 1.22 +app.html_title.title = initiative.name 1.23 +app.html_title.subtitle = _("Initiative ##{id}", { id = initiative.id }) 1.24 + 1.25 +slot.select("head", function() 1.26 + execute.view{ 1.27 + module = "issue", view = "_head", 1.28 + params = { issue = issue, initiative = initiative } 1.29 + } 1.30 +end) 1.31 + 1.32 +local initiators_members_selector = initiative:get_reference_selector("initiating_members") 1.33 + :add_field("initiator.accepted", "accepted") 1.34 + :add_order_by("member.name") 1.35 +if initiator and initiator.accepted then 1.36 + initiators_members_selector:add_where("initiator.accepted ISNULL OR initiator.accepted") 1.37 +else 1.38 + initiators_members_selector:add_where("initiator.accepted") 1.39 +end 1.40 + 1.41 +local initiators = initiators_members_selector:exec() 1.42 + 1.43 + 1.44 +local initiatives_selector = initiative.issue:get_reference_selector("initiatives") 1.45 +slot.select("head", function() 1.46 + execute.view{ 1.47 + module = "issue", 1.48 + view = "_show", 1.49 + params = { 1.50 + issue = initiative.issue, 1.51 + initiative_limit = 3, 1.52 + for_initiative = initiative 1.53 + } 1.54 + } 1.55 +end) 1.56 + 1.57 +util.help("initiative.show") 1.58 + 1.59 +ui.container{ attr = { class = "initiative_head" }, content = function() 1.60 + 1.61 + local text = _("Initiative i#{id}: #{name}", { id = initiative.id, name = initiative.name }) 1.62 + if show_as_head then 1.63 + ui.link{ 1.64 + attr = { class = "title" }, text = text, 1.65 + module = "initiative", view = "show", id = initiative.id 1.66 + } 1.67 + else 1.68 + ui.container{ attr = { class = "title" }, content = text } 1.69 + end 1.70 + ui.container{ attr = { class = "content" }, content = function() 1.71 + if app.session.member_id or config.public_access == "pseudonym" or config.public_access == "full" then 1.72 + ui.tag{ 1.73 + attr = { class = "initiator_names" }, 1.74 + content = function() 1.75 + for i, initiator in ipairs(initiators) do 1.76 + slot.put(" ") 1.77 + if app.session.member_id or config.public_access == "full" then 1.78 + ui.link{ 1.79 + content = function () 1.80 + execute.view{ 1.81 + module = "member_image", 1.82 + view = "_show", 1.83 + params = { 1.84 + member = initiator, 1.85 + image_type = "avatar", 1.86 + show_dummy = true, 1.87 + class = "micro_avatar", 1.88 + popup_text = text 1.89 + } 1.90 + } 1.91 + end, 1.92 + module = "member", view = "show", id = initiator.id 1.93 + } 1.94 + slot.put(" ") 1.95 + end 1.96 + ui.link{ 1.97 + text = initiator.name, 1.98 + module = "member", view = "show", id = initiator.id 1.99 + } 1.100 + if not initiator.accepted then 1.101 + ui.tag{ attr = { title = _"Not accepted yet" }, content = "?" } 1.102 + end 1.103 + end 1.104 + if initiator and initiator.accepted and not initiative.issue.fully_frozen and not initiative.issue.closed and not initiative.revoked then 1.105 + slot.put(" · ") 1.106 + ui.link{ 1.107 + attr = { class = "action" }, 1.108 + content = function() 1.109 + slot.put(_"Invite initiator") 1.110 + end, 1.111 + module = "initiative", 1.112 + view = "add_initiator", 1.113 + params = { initiative_id = initiative.id } 1.114 + } 1.115 + if #initiators > 1 then 1.116 + slot.put(" · ") 1.117 + ui.link{ 1.118 + content = function() 1.119 + slot.put(_"Remove initiator") 1.120 + end, 1.121 + module = "initiative", 1.122 + view = "remove_initiator", 1.123 + params = { initiative_id = initiative.id } 1.124 + } 1.125 + end 1.126 + end 1.127 + if initiator and initiator.accepted == false then 1.128 + slot.put(" · ") 1.129 + ui.link{ 1.130 + text = _"Cancel refuse of invitation", 1.131 + module = "initiative", 1.132 + action = "remove_initiator", 1.133 + params = { 1.134 + initiative_id = initiative.id, 1.135 + member_id = app.session.member.id 1.136 + }, 1.137 + routing = { 1.138 + ok = { 1.139 + mode = "redirect", 1.140 + module = "initiative", 1.141 + view = "show", 1.142 + id = initiative.id 1.143 + } 1.144 + } 1.145 + } 1.146 + end 1.147 + if (initiative.discussion_url and #initiative.discussion_url > 0) then 1.148 + slot.put(" · ") 1.149 + if initiative.discussion_url:find("^https?://") then 1.150 + if initiative.discussion_url and #initiative.discussion_url > 0 then 1.151 + ui.link{ 1.152 + attr = { 1.153 + target = "_blank", 1.154 + title = _"Discussion with initiators" 1.155 + }, 1.156 + text = _"Discuss with initiators", 1.157 + external = initiative.discussion_url 1.158 + } 1.159 + end 1.160 + else 1.161 + slot.put(encode.html(initiative.discussion_url)) 1.162 + end 1.163 + end 1.164 + if initiator and initiator.accepted and not initiative.issue.half_frozen and not initiative.issue.closed and not initiative.revoked then 1.165 + slot.put(" · ") 1.166 + ui.link{ 1.167 + text = _"change discussion URL", 1.168 + module = "initiative", 1.169 + view = "edit", 1.170 + id = initiative.id 1.171 + } 1.172 + slot.put(" ") 1.173 + end 1.174 + end 1.175 + } 1.176 + end 1.177 + 1.178 + end } 1.179 + ui.container{ attr = { class = "content" }, content = function() 1.180 + if app.session.member_id then 1.181 + execute.view{ 1.182 + module = "supporter", 1.183 + view = "_show_box", 1.184 + params = { 1.185 + initiative = initiative 1.186 + } 1.187 + } 1.188 + end 1.189 + 1.190 + end } 1.191 + 1.192 + 1.193 + -- voting results 1.194 + if initiative.issue.ranks_available and initiative.admitted then 1.195 + local class = initiative.winner and "admitted_info" or "not_admitted_info" 1.196 + ui.container{ 1.197 + attr = { class = class }, 1.198 + content = function() 1.199 + local max_value = initiative.issue.voter_count 1.200 + slot.put(" ") 1.201 + local positive_votes = initiative.positive_votes 1.202 + local negative_votes = initiative.negative_votes 1.203 + local sum_votes = initiative.positive_votes + initiative.negative_votes 1.204 + local function perc(votes, sum) 1.205 + if sum > 0 and votes > 0 then return " (" .. string.format( "%.f", votes * 100 / sum ) .. "%)" end 1.206 + return "" 1.207 + end 1.208 + slot.put(_"Yes" .. ": <b>" .. tostring(positive_votes) .. perc(positive_votes, sum_votes) .. "</b>") 1.209 + slot.put(" · ") 1.210 + slot.put(_"Abstention" .. ": <b>" .. tostring(max_value - initiative.negative_votes - initiative.positive_votes) .. "</b>") 1.211 + slot.put(" · ") 1.212 + slot.put(_"No" .. ": <b>" .. tostring(initiative.negative_votes) .. perc(negative_votes, sum_votes) .. "</b>") 1.213 + slot.put(" · ") 1.214 + slot.put("<b>") 1.215 + if initiative.winner then 1.216 + slot.put(_"Approved") 1.217 + elseif initiative.rank then 1.218 + slot.put(_("Not approved (rank #{rank})", { rank = initiative.rank })) 1.219 + else 1.220 + slot.put(_"Not approved") 1.221 + end 1.222 + slot.put("</b>") 1.223 + end 1.224 + } 1.225 + end 1.226 + 1.227 + ui.container{ attr = { class = "content" }, content = function() 1.228 + execute.view{ 1.229 + module = "initiative", 1.230 + view = "_battles", 1.231 + params = { initiative = initiative } 1.232 + } 1.233 + end } 1.234 + 1.235 + -- initiative not admitted info 1.236 + if initiative.admitted == false then 1.237 + local policy = initiative.issue.policy 1.238 + ui.container{ 1.239 + attr = { class = "not_admitted_info" }, 1.240 + content = _("This initiative has not been admitted! It failed the quorum of #{quorum}.", { quorum = format.percentage(policy.initiative_quorum_num / policy.initiative_quorum_den) }) 1.241 + } 1.242 + end 1.243 + 1.244 + -- initiative revoked info 1.245 + if initiative.revoked then 1.246 + ui.container{ 1.247 + attr = { class = "revoked_info" }, 1.248 + content = function() 1.249 + slot.put(_("This initiative has been revoked at #{revoked}", { revoked = format.timestamp(initiative.revoked) })) 1.250 + local suggested_initiative = initiative.suggested_initiative 1.251 + if suggested_initiative then 1.252 + slot.put("<br /><br />") 1.253 + slot.put(_("The initiators suggest to support the following initiative:")) 1.254 + slot.put(" ") 1.255 + ui.link{ 1.256 + content = _("Issue ##{id}", { id = suggested_initiative.issue.id } ) .. ": " .. encode.html(suggested_initiative.name), 1.257 + module = "initiative", 1.258 + view = "show", 1.259 + id = suggested_initiative.id 1.260 + } 1.261 + end 1.262 + end 1.263 + } 1.264 + end 1.265 + 1.266 + 1.267 + -- invited as initiator 1.268 + if initiator and initiator.accepted == nil and not initiative.issue.half_frozen and not initiative.issue.closed then 1.269 + ui.container{ 1.270 + attr = { class = "initiator_invite_info" }, 1.271 + content = function() 1.272 + slot.put(_"You are invited to become initiator of this initiative.") 1.273 + slot.put(" ") 1.274 + ui.link{ 1.275 + image = { static = "icons/16/tick.png" }, 1.276 + text = _"Accept invitation", 1.277 + module = "initiative", 1.278 + action = "accept_invitation", 1.279 + id = initiative.id, 1.280 + routing = { 1.281 + default = { 1.282 + mode = "redirect", 1.283 + module = request.get_module(), 1.284 + view = request.get_view(), 1.285 + id = param.get_id_cgi(), 1.286 + params = param.get_all_cgi() 1.287 + } 1.288 + } 1.289 + } 1.290 + slot.put(" ") 1.291 + ui.link{ 1.292 + image = { static = "icons/16/cross.png" }, 1.293 + text = _"Refuse invitation", 1.294 + module = "initiative", 1.295 + action = "reject_initiator_invitation", 1.296 + params = { 1.297 + initiative_id = initiative.id, 1.298 + member_id = app.session.member.id 1.299 + }, 1.300 + routing = { 1.301 + default = { 1.302 + mode = "redirect", 1.303 + module = request.get_module(), 1.304 + view = request.get_view(), 1.305 + id = param.get_id_cgi(), 1.306 + params = param.get_all_cgi() 1.307 + } 1.308 + } 1.309 + } 1.310 + end 1.311 + } 1.312 + end 1.313 + 1.314 + -- draft updated 1.315 + local supporter 1.316 + 1.317 + if app.session.member_id then 1.318 + supporter = app.session.member:get_reference_selector("supporters") 1.319 + :add_where{ "initiative_id = ?", initiative.id } 1.320 + :optional_object_mode() 1.321 + :exec() 1.322 + end 1.323 + 1.324 + if supporter and not initiative.issue.closed then 1.325 + local old_draft_id = supporter.draft_id 1.326 + local new_draft_id = initiative.current_draft.id 1.327 + if old_draft_id ~= new_draft_id then 1.328 + ui.container{ 1.329 + attr = { class = "draft_updated_info" }, 1.330 + content = function() 1.331 + slot.put(_"The draft of this initiative has been updated!") 1.332 + slot.put(" ") 1.333 + ui.link{ 1.334 + content = _"Show diff", 1.335 + module = "draft", 1.336 + view = "diff", 1.337 + params = { 1.338 + old_draft_id = old_draft_id, 1.339 + new_draft_id = new_draft_id 1.340 + } 1.341 + } 1.342 + if not initiative.revoked then 1.343 + slot.put(" ") 1.344 + ui.link{ 1.345 + text = _"Refresh support to current draft", 1.346 + module = "initiative", 1.347 + action = "add_support", 1.348 + id = initiative.id, 1.349 + routing = { 1.350 + default = { 1.351 + mode = "redirect", 1.352 + module = "initiative", 1.353 + view = "show", 1.354 + id = initiative.id 1.355 + } 1.356 + } 1.357 + } 1.358 + end 1.359 + end 1.360 + } 1.361 + end 1.362 + end 1.363 + 1.364 + if not show_as_head then 1.365 + local drafts_count = initiative:get_reference_selector("drafts"):count() 1.366 + 1.367 + ui.container{ attr = { class = "content" }, content = function() 1.368 + 1.369 + if initiator and initiator.accepted and not initiative.issue.half_frozen and not initiative.issue.closed and not initiative.revoked then 1.370 + ui.link{ 1.371 + content = function() 1.372 + slot.put(_"Edit draft") 1.373 + end, 1.374 + module = "draft", 1.375 + view = "new", 1.376 + params = { initiative_id = initiative.id } 1.377 + } 1.378 + slot.put(" · ") 1.379 + ui.link{ 1.380 + content = function() 1.381 + slot.put(_"Revoke initiative") 1.382 + end, 1.383 + module = "initiative", 1.384 + view = "revoke", 1.385 + id = initiative.id 1.386 + } 1.387 + slot.put(" · ") 1.388 + end 1.389 + 1.390 + ui.tag{ 1.391 + attr = { class = "draft_version" }, 1.392 + content = _("Latest draft created at #{date} #{time}", { 1.393 + date = format.date(initiative.current_draft.created), 1.394 + time = format.time(initiative.current_draft.created) 1.395 + }) 1.396 + } 1.397 + if drafts_count > 1 then 1.398 + slot.put(" · ") 1.399 + ui.link{ 1.400 + module = "draft", view = "list", params = { initiative_id = initiative.id }, 1.401 + text = _("List all revisions (#{count})", { count = drafts_count }) 1.402 + } 1.403 + end 1.404 + end } 1.405 + 1.406 + execute.view{ 1.407 + module = "draft", 1.408 + view = "_show", 1.409 + params = { 1.410 + draft = initiative.current_draft 1.411 + } 1.412 + } 1.413 + end 1.414 +end } 1.415 + 1.416 +if not show_as_head then 1.417 + execute.view{ 1.418 + module = "suggestion", 1.419 + view = "_list", 1.420 + params = { 1.421 + initiative = initiative, 1.422 + suggestions_selector = initiative:get_reference_selector("suggestions"), 1.423 + tab_id = param.get("tab_id") 1.424 + } 1.425 + } 1.426 + 1.427 + 1.428 + if config.public_access == "full" or app.session.member_id then 1.429 + if initiative.issue.ranks_available then 1.430 + local members_selector = initiative.issue:get_reference_selector("direct_voters") 1.431 + :left_join("vote", nil, { "vote.initiative_id = ? AND vote.member_id = member.id", initiative.id }) 1.432 + :add_field("direct_voter.weight as voter_weight") 1.433 + :add_field("coalesce(vote.grade, 0) as grade") 1.434 + :left_join("initiative", nil, "initiative.id = vote.initiative_id") 1.435 + :left_join("issue", nil, "issue.id = initiative.issue_id") 1.436 + 1.437 + ui.anchor{ name = "voter", attr = { class = "heading" }, content = _"Member voter" } 1.438 + 1.439 + execute.view{ 1.440 + module = "member", 1.441 + view = "_list", 1.442 + params = { 1.443 + initiative = initiative, 1.444 + for_votes = true, 1.445 + members_selector = members_selector, 1.446 + paginator_name = "voter" 1.447 + } 1.448 + } 1.449 + end 1.450 + 1.451 + local members_selector = initiative:get_reference_selector("supporting_members_snapshot") 1.452 + :join("issue", nil, "issue.id = direct_supporter_snapshot.issue_id") 1.453 + :join("direct_interest_snapshot", nil, "direct_interest_snapshot.event = issue.latest_snapshot_event AND direct_interest_snapshot.issue_id = issue.id AND direct_interest_snapshot.member_id = member.id") 1.454 + :add_field("direct_interest_snapshot.weight") 1.455 + :add_where("direct_supporter_snapshot.event = issue.latest_snapshot_event") 1.456 + :add_where("direct_supporter_snapshot.satisfied") 1.457 + :add_field("direct_supporter_snapshot.informed", "is_informed") 1.458 + 1.459 + if members_selector:count() > 0 then 1.460 + if issue.fully_frozen then 1.461 + ui.anchor{ name = "supporters", attr = { class = "heading" }, content = _"Supporters (before begin of voting)" } 1.462 + else 1.463 + ui.anchor{ name = "supporters", attr = { class = "heading" }, content = _"Supporters" } 1.464 + end 1.465 + 1.466 + execute.view{ 1.467 + module = "member", 1.468 + view = "_list", 1.469 + params = { 1.470 + initiative = initiative, 1.471 + members_selector = members_selector, 1.472 + paginator_name = "supporters" 1.473 + } 1.474 + } 1.475 + else 1.476 + if issue.fully_frozen then 1.477 + ui.anchor{ name = "supporters", attr = { class = "heading" }, content = _"No supporters (before begin of voting)" } 1.478 + else 1.479 + ui.anchor{ name = "supporters", attr = { class = "heading" }, content = _"No supporters" } 1.480 + end 1.481 + slot.put("<br />") 1.482 + end 1.483 + 1.484 + local members_selector = initiative:get_reference_selector("supporting_members_snapshot") 1.485 + :join("issue", nil, "issue.id = direct_supporter_snapshot.issue_id") 1.486 + :join("direct_interest_snapshot", nil, "direct_interest_snapshot.event = issue.latest_snapshot_event AND direct_interest_snapshot.issue_id = issue.id AND direct_interest_snapshot.member_id = member.id") 1.487 + :add_field("direct_interest_snapshot.weight") 1.488 + :add_where("direct_supporter_snapshot.event = issue.latest_snapshot_event") 1.489 + :add_where("NOT direct_supporter_snapshot.satisfied") 1.490 + :add_field("direct_supporter_snapshot.informed", "is_informed") 1.491 + 1.492 + if members_selector:count() > 0 then 1.493 + if issue.fully_frozen then 1.494 + ui.anchor{ name = "potential_supporters", attr = { class = "heading" }, content = _"Potential supporters (before begin of voting)" } 1.495 + else 1.496 + ui.anchor{ name = "potential_supporters", attr = { class = "heading" }, content = _"Potential supporters" } 1.497 + end 1.498 + 1.499 + execute.view{ 1.500 + module = "member", 1.501 + view = "_list", 1.502 + params = { 1.503 + initiative = initiative, 1.504 + members_selector = members_selector, 1.505 + paginator_name = "potential_supporters" 1.506 + } 1.507 + } 1.508 + else 1.509 + if issue.fully_frozen then 1.510 + ui.anchor{ name = "potential_supporters", attr = { class = "heading" }, content = _"No potential supporters (before begin of voting)" } 1.511 + else 1.512 + ui.anchor{ name = "potential_supporters", attr = { class = "heading" }, content = _"No potential supporters" } 1.513 + end 1.514 + slot.put("<br />") 1.515 + end 1.516 + 1.517 + ui.container{ attr = { class = "heading" }, content = _"Details" } 1.518 + execute.view { 1.519 + module = "initiative", 1.520 + view = "_details", 1.521 + params = { 1.522 + initiative = initiative, 1.523 + members_selector = members_selector 1.524 + } 1.525 + } 1.526 + 1.527 + end 1.528 +end 1.529 \ No newline at end of file