| rev | line source | 
| bsw/jbe@0 | 1 Issue = mondelefant.new_class() | 
| bsw/jbe@0 | 2 Issue.table = 'issue' | 
| bsw/jbe@0 | 3 | 
| bsw@549 | 4 local new_selector = Issue.new_selector | 
| bsw@549 | 5 | 
| bsw@549 | 6 function Issue:new_selector() | 
| bsw@549 | 7   local selector = new_selector(self) | 
| bsw@935 | 8   selector:add_field("justify_interval(admission_time)::text", "admission_time_text") | 
| bsw@935 | 9   selector:add_field("justify_interval(discussion_time)::text", "discussion_time_text") | 
| bsw@935 | 10   selector:add_field("justify_interval(verification_time)::text", "verification_time_text") | 
| bsw@935 | 11   selector:add_field("justify_interval(voting_time)::text", "voting_time_text") | 
| bsw@935 | 12   selector:add_field("justify_interval(coalesce(issue.fully_frozen + issue.voting_time, issue.half_frozen + issue.verification_time, issue.accepted + issue.discussion_time, issue.created + issue.admission_time) - now())", "state_time_left") | 
| bsw@935 | 13   selector:add_field("justify_interval(now() - issue.closed)", "closed_ago") | 
| bsw@549 | 14   return selector | 
| bsw@549 | 15 end | 
| bsw@549 | 16 | 
| bsw/jbe@0 | 17 Issue:add_reference{ | 
| bsw/jbe@0 | 18   mode          = 'm1', | 
| bsw/jbe@0 | 19   to            = "Area", | 
| bsw/jbe@0 | 20   this_key      = 'area_id', | 
| bsw/jbe@0 | 21   that_key      = 'id', | 
| bsw/jbe@0 | 22   ref           = 'area', | 
| bsw/jbe@0 | 23 } | 
| bsw/jbe@0 | 24 | 
| bsw/jbe@0 | 25 Issue:add_reference{ | 
| bsw/jbe@0 | 26   mode          = 'm1', | 
| bsw/jbe@0 | 27   to            = "Policy", | 
| bsw/jbe@0 | 28   this_key      = 'policy_id', | 
| bsw/jbe@0 | 29   that_key      = 'id', | 
| bsw/jbe@0 | 30   ref           = 'policy', | 
| bsw/jbe@0 | 31 } | 
| bsw/jbe@0 | 32 | 
| bsw/jbe@0 | 33 Issue:add_reference{ | 
| bsw/jbe@0 | 34   mode          = '1m', | 
| bsw/jbe@0 | 35   to            = "Initiative", | 
| bsw/jbe@0 | 36   this_key      = 'id', | 
| bsw/jbe@0 | 37   that_key      = 'issue_id', | 
| bsw/jbe@0 | 38   ref           = 'initiatives', | 
| bsw@551 | 39   back_ref      = 'issue', | 
| bsw@982 | 40   default_order = 'initiative.admitted DESC NULLS LAST, initiative.rank NULLS LAST, initiative.harmonic_weight DESC NULLS LAST, id' | 
| bsw/jbe@0 | 41 } | 
| bsw/jbe@0 | 42 | 
| bsw/jbe@0 | 43 Issue:add_reference{ | 
| bsw/jbe@0 | 44   mode          = '1m', | 
| bsw/jbe@0 | 45   to            = "Interest", | 
| bsw/jbe@0 | 46   this_key      = 'id', | 
| bsw/jbe@0 | 47   that_key      = 'issue_id', | 
| bsw/jbe@0 | 48   ref           = 'interests', | 
| bsw/jbe@0 | 49   back_ref      = 'issue', | 
| bsw/jbe@0 | 50   default_order = '"id"' | 
| bsw/jbe@0 | 51 } | 
| bsw/jbe@0 | 52 | 
| bsw/jbe@0 | 53 Issue:add_reference{ | 
| bsw/jbe@0 | 54   mode          = '1m', | 
| bsw/jbe@0 | 55   to            = "Supporter", | 
| bsw/jbe@0 | 56   this_key      = 'id', | 
| bsw/jbe@0 | 57   that_key      = 'issue_id', | 
| bsw/jbe@0 | 58   ref           = 'supporters', | 
| bsw/jbe@0 | 59   back_ref      = 'issue', | 
| bsw/jbe@0 | 60   default_order = '"id"' | 
| bsw/jbe@0 | 61 } | 
| bsw/jbe@0 | 62 | 
| bsw/jbe@0 | 63 Issue:add_reference{ | 
| bsw/jbe@0 | 64   mode          = '1m', | 
| bsw/jbe@0 | 65   to            = "DirectVoter", | 
| bsw/jbe@0 | 66   this_key      = 'id', | 
| bsw/jbe@0 | 67   that_key      = 'issue_id', | 
| bsw/jbe@0 | 68   ref           = 'direct_voters', | 
| bsw/jbe@0 | 69   back_ref      = 'issue', | 
| bsw/jbe@0 | 70   default_order = '"member_id"' | 
| bsw/jbe@0 | 71 } | 
| bsw/jbe@0 | 72 | 
| bsw/jbe@0 | 73 Issue:add_reference{ | 
| bsw/jbe@0 | 74   mode          = '1m', | 
| bsw/jbe@0 | 75   to            = "Vote", | 
| bsw/jbe@0 | 76   this_key      = 'id', | 
| bsw/jbe@0 | 77   that_key      = 'issue_id', | 
| bsw/jbe@0 | 78   ref           = 'votes', | 
| bsw/jbe@0 | 79   back_ref      = 'issue', | 
| bsw/jbe@0 | 80   default_order = '"member_id", "initiative_id"' | 
| bsw/jbe@0 | 81 } | 
| bsw/jbe@0 | 82 | 
| bsw/jbe@0 | 83 Issue:add_reference{ | 
| bsw@2 | 84   mode          = '1m', | 
| bsw@2 | 85   to            = "Delegation", | 
| bsw@2 | 86   this_key      = 'id', | 
| bsw@2 | 87   that_key      = 'issue_id', | 
| bsw@2 | 88   ref           = 'delegations', | 
| bsw@2 | 89   back_ref      = 'issue' | 
| bsw@2 | 90 } | 
| bsw@2 | 91 | 
| bsw@2 | 92 Issue:add_reference{ | 
| bsw/jbe@0 | 93   mode                  = 'mm', | 
| bsw/jbe@0 | 94   to                    = "Member", | 
| bsw/jbe@0 | 95   this_key              = 'id', | 
| bsw/jbe@0 | 96   that_key              = 'id', | 
| bsw/jbe@0 | 97   connected_by_table    = 'interest', | 
| bsw/jbe@0 | 98   connected_by_this_key = 'issue_id', | 
| bsw/jbe@0 | 99   connected_by_that_key = 'member_id', | 
| bsw/jbe@0 | 100   ref                   = 'members' | 
| bsw/jbe@0 | 101 } | 
| bsw/jbe@0 | 102 | 
| bsw@3 | 103 Issue:add_reference{ | 
| bsw@3 | 104   mode                  = 'mm', | 
| bsw@3 | 105   to                    = "Member", | 
| bsw@3 | 106   this_key              = 'id', | 
| bsw@3 | 107   that_key              = 'id', | 
| bsw@3 | 108   connected_by_table    = 'direct_interest_snapshot', | 
| bsw@3 | 109   connected_by_this_key = 'issue_id', | 
| bsw@3 | 110   connected_by_that_key = 'member_id', | 
| bsw@3 | 111   ref                   = 'interested_members_snapshot' | 
| bsw@3 | 112 } | 
| bsw@3 | 113 | 
| bsw/jbe@6 | 114 Issue:add_reference{ | 
| bsw/jbe@6 | 115   mode                  = 'mm', | 
| bsw/jbe@6 | 116   to                    = "Member", | 
| bsw/jbe@6 | 117   this_key              = 'id', | 
| bsw/jbe@6 | 118   that_key              = 'id', | 
| bsw/jbe@6 | 119   connected_by_table    = 'direct_voter', | 
| bsw/jbe@6 | 120   connected_by_this_key = 'issue_id', | 
| bsw/jbe@6 | 121   connected_by_that_key = 'member_id', | 
| bsw/jbe@6 | 122   ref                   = 'direct_voters' | 
| bsw/jbe@6 | 123 } | 
| bsw/jbe@6 | 124 | 
| bsw@525 | 125 Issue:add_reference{ | 
| bsw@525 | 126   mode               = "11", | 
| bsw@525 | 127   to                 = mondelefant.class_prototype, | 
| bsw@525 | 128   this_key           = "id", | 
| bsw@525 | 129   that_key           = "issue_id", | 
| bsw@547 | 130   ref                = "member_info", | 
| bsw@525 | 131   back_ref           = "issue", | 
| bsw@525 | 132   selector_generator = function(list, options) | 
| bsw@547 | 133     assert(options.member_id, "member_id mandatory for member_info") | 
| bsw@525 | 134     local ids = { sep = ", " } | 
| bsw@525 | 135     for i, object in ipairs(list) do | 
| bsw@525 | 136       local id = object.id | 
| bsw@525 | 137       if id ~= nil then | 
| bsw@525 | 138         ids[#ids+1] = {"?", id} | 
| bsw@525 | 139       end | 
| bsw@525 | 140     end | 
| bsw@525 | 141     local sub_selector = Issue:get_db_conn():new_selector() | 
| bsw@525 | 142     if #ids == 0 then | 
| bsw@525 | 143       return sub_selector:empty_list_mode() | 
| bsw@525 | 144     end | 
| bsw@1045 | 145     sub_selector:from ( "issue" ) | 
| bsw@1045 | 146     sub_selector:add_field ( "issue.id", "issue_id" ) | 
| bsw@1045 | 147     sub_selector:add_field { '(delegation_info(?, null, null, issue.id, ?)).*', options.member_id, options.trustee_id } | 
| bsw@1045 | 148     sub_selector:add_where { 'issue.id IN ($)', ids } | 
| bsw@525 | 149 | 
| bsw@525 | 150     local selector = Issue:get_db_conn():new_selector() | 
| bsw@1045 | 151     selector:add_from ( "issue" ) | 
| bsw@1045 | 152     selector:join(sub_selector, "delegation_info", "delegation_info.issue_id = issue.id" ) | 
| bsw@1045 | 153     selector:left_join ( "member", "first_trustee", "first_trustee.id = delegation_info.first_trustee_id" ) | 
| bsw@1045 | 154     selector:left_join ( "member", "other_trustee", "other_trustee.id = delegation_info.other_trustee_id" ) | 
| bsw@1045 | 155     selector:add_field ( "delegation_info.*" ) | 
| bsw@1045 | 156     selector:add_field ( "first_trustee.name", "first_trustee_name" ) | 
| bsw@1045 | 157     selector:add_field ( "other_trustee.name", "other_trustee_name" ) | 
| bsw@1045 | 158     selector:left_join ( "direct_voter", nil, { "direct_voter.issue_id = issue.id AND direct_voter.member_id = ?", options.member_id }) | 
| bsw@1045 | 159     selector:add_field ( "direct_voter.member_id NOTNULL", "direct_voted") | 
| bsw@1045 | 160     selector:left_join ( "non_voter", nil, { "non_voter.issue_id = issue.id AND non_voter.member_id = ?", options.member_id }) | 
| bsw@1045 | 161     selector:add_field ( "non_voter.member_id NOTNULL", "non_voter" ) | 
| bsw@1045 | 162     selector:left_join ( "direct_interest_snapshot", nil, { [[ | 
| bsw@1045 | 163       direct_interest_snapshot.issue_id = issue.id AND | 
| bsw@1045 | 164       direct_interest_snapshot.event = issue.latest_snapshot_event AND | 
| bsw@1045 | 165       direct_interest_snapshot.member_id = ? | 
| bsw@1045 | 166     ]], options.member_id }) | 
| bsw@1045 | 167     selector:add_field ( "direct_interest_snapshot.weight", "weight" ) | 
| bsw@525 | 168     return selector | 
| bsw@525 | 169   end | 
| bsw@525 | 170 } | 
| bsw@525 | 171 | 
| bsw@547 | 172 function Issue.list:load_everything_for_member_id(member_id) | 
| bsw@547 | 173   local areas = self:load("area") | 
| bsw@547 | 174   areas:load("unit") | 
| bsw@547 | 175   self:load("policy") | 
| bsw@551 | 176   if member_id then | 
| bsw@551 | 177     self:load("member_info", { member_id = member_id }) | 
| bsw@551 | 178   end | 
| bsw@551 | 179   local initiatives = self:load("initiatives") | 
| bsw@551 | 180   initiatives:load_everything_for_member_id(member_id) | 
| bsw@525 | 181 end | 
| bsw@525 | 182 | 
| bsw@548 | 183 function Issue.object:load_everything_for_member_id(member_id) | 
| bsw@548 | 184   local areas = self:load("area") | 
| bsw@548 | 185   areas:load("unit") | 
| bsw@548 | 186   self:load("policy") | 
| bsw@551 | 187   if member_id then | 
| bsw@551 | 188     self:load("member_info", { member_id = member_id }) | 
| bsw@551 | 189   end | 
| bsw@551 | 190   local initiatives = self:load("initiatives") | 
| bsw@551 | 191   initiatives:load_everything_for_member_id(member_id) | 
| bsw@548 | 192 end | 
| bsw@548 | 193 | 
| bsw@972 | 194 | 
| bsw@972 | 195 | 
| bsw/jbe@0 | 196 function Issue:get_state_name_for_state(value) | 
| bsw@2 | 197   local state_name_table = { | 
| bsw@1045 | 198     admission = _"Admission", | 
| bsw@972 | 199     discussion = _"Discussion", | 
| bsw@1045 | 200     verification = _"Verification", | 
| bsw@972 | 201     voting = _"Voting", | 
| bsw@1045 | 202     canceled_revoked_before_accepted = _"Revoked (during admission)", | 
| bsw@1045 | 203     canceled_issue_not_accepted = _"Failed 1st quorum", | 
| bsw@1045 | 204     canceled_after_revocation_during_discussion = _"Revoked (during discussion)", | 
| bsw@1045 | 205     canceled_after_revocation_during_verification = _"Revoked (during verification)", | 
| bsw@1029 | 206     canceled_by_admin = _"Canceled by administrative intervention", | 
| bsw@972 | 207     calculation = _"Calculation", | 
| bsw@1045 | 208     canceled_no_initiative_admitted = _"All initiatives failed 2nd quorum", | 
| bsw@1045 | 209     finished_without_winner = _"Disapproved", | 
| bsw@1045 | 210     finished_with_winner = _"Finished with winner", | 
| bsw@2 | 211   } | 
| bsw@10 | 212   return state_name_table[value] or value or '' | 
| bsw/jbe@0 | 213 end | 
| bsw/jbe@0 | 214 | 
| bsw@972 | 215 | 
| bsw@972 | 216 | 
| bsw@2 | 217 function Issue:get_search_selector(search_string) | 
| bsw/jbe@0 | 218   return self:new_selector() | 
| bsw/jbe@0 | 219     :join('"initiative"', nil, '"initiative"."issue_id" = "issue"."id"') | 
| bsw/jbe@6 | 220     :join('"draft"', nil, '"draft"."initiative_id" = "initiative"."id"') | 
| bsw/jbe@6 | 221     :add_where{ '"initiative"."text_search_data" @@ "text_search_query"(?) OR "draft"."text_search_data" @@ "text_search_query"(?)', search_string, search_string } | 
| bsw/jbe@6 | 222     :add_group_by('"issue"."id"') | 
| bsw@976 | 223     :add_group_by('"issue"."area_id"') | 
| bsw@976 | 224     :add_group_by('"issue"."policy_id"') | 
| bsw@977 | 225     :add_group_by('"issue"."state"') | 
| bsw@977 | 226     :add_group_by('"issue"."phase_finished"') | 
| bsw@976 | 227     :add_group_by('"issue"."created"') | 
| bsw@976 | 228     :add_group_by('"issue"."accepted"') | 
| bsw@976 | 229     :add_group_by('"issue"."half_frozen"') | 
| bsw@976 | 230     :add_group_by('"issue"."fully_frozen"') | 
| bsw@976 | 231     :add_group_by('"issue"."closed"') | 
| bsw@976 | 232     :add_group_by('"issue"."status_quo_schulze_rank"') | 
| bsw@976 | 233     :add_group_by('"issue"."cleaned"') | 
| bsw@976 | 234     :add_group_by('"issue"."snapshot"') | 
| bsw@976 | 235     :add_group_by('"issue"."latest_snapshot_event"') | 
| bsw@976 | 236     :add_group_by('"issue"."population"') | 
| bsw@976 | 237     :add_group_by('"issue"."voter_count"') | 
| bsw@976 | 238     :add_group_by('"issue"."admission_time"') | 
| bsw@976 | 239     :add_group_by('"issue"."discussion_time"') | 
| bsw@976 | 240     :add_group_by('"issue"."verification_time"') | 
| bsw@976 | 241     :add_group_by('"issue"."voting_time"') | 
| bsw@1038 | 242     :add_group_by('"issue"."admin_notice"') | 
| bsw@976 | 243     --:set_distinct() | 
| bsw/jbe@0 | 244 end | 
| bsw/jbe@0 | 245 | 
| bsw@75 | 246 function Issue:modify_selector_for_state(initiatives_selector, state) | 
| bsw@51 | 247   if state == "new" then | 
| bsw@75 | 248     initiatives_selector:add_where("issue.accepted ISNULL AND issue.closed ISNULL") | 
| bsw@51 | 249   elseif state == "accepted" then | 
| bsw@75 | 250     initiatives_selector:add_where("issue.accepted NOTNULL AND issue.half_frozen ISNULL AND issue.closed ISNULL") | 
| bsw@51 | 251   elseif state == "frozen" then | 
| bsw@75 | 252     initiatives_selector:add_where("issue.half_frozen NOTNULL AND issue.fully_frozen ISNULL AND issue.closed ISNULL") | 
| bsw@51 | 253   elseif state == "voting" then | 
| bsw@75 | 254     initiatives_selector:add_where("issue.fully_frozen NOTNULL AND issue.closed ISNULL") | 
| bsw@51 | 255   elseif state == "finished" then | 
| bsw@75 | 256     initiatives_selector:add_where("issue.fully_frozen NOTNULL AND issue.closed NOTNULL") | 
| bsw@973 | 257   elseif state == "canceled" then | 
| bsw@75 | 258     initiatives_selector:add_where("issue.fully_frozen ISNULL AND issue.closed NOTNULL") | 
| bsw@75 | 259   else | 
| bsw@75 | 260     error("Invalid state") | 
| bsw@51 | 261   end | 
| bsw@51 | 262 end | 
| bsw@51 | 263 | 
| bsw@2 | 264 | 
| bsw@2 | 265 function Issue.object_get:state_name() | 
| bsw@2 | 266   return Issue:get_state_name_for_state(self.state) | 
| bsw@2 | 267 end | 
| bsw@2 | 268 | 
| bsw@2 | 269 function Issue.object_get:next_states_names() | 
| bsw@2 | 270   local next_states = self.next_states | 
| bsw@2 | 271   if not next_states then | 
| bsw@2 | 272     return | 
| bsw@2 | 273   end | 
| bsw@2 | 274   local state_names = {} | 
| bsw@2 | 275   for i, state in ipairs(self.next_states) do | 
| bsw@2 | 276     state_names[#state_names+1] = Issue:get_state_name_for_state(state) | 
| bsw@2 | 277   end | 
| bsw@2 | 278   return table.concat(state_names, ", ") | 
| bsw@525 | 279 end | 
| bsw@525 | 280 | 
| bsw@525 | 281 function Issue.object_get:etherpad_url() | 
| bsw@525 | 282   return config.etherpad.base_url .. "p/" .. config.etherpad.group_id .. "$Issue" .. self.id | 
| bsw@551 | 283 end | 
| bsw@1045 | 284 | 
| bsw@1045 | 285 function Issue.object_get:name() | 
| bsw@1045 | 286   return self.policy.name .. " #" .. self.id | 
| bsw@1045 | 287 end | 
| bsw@1045 | 288 | 
| bsw@1045 | 289 function Issue.object_get:state_time_text() | 
| bsw@1045 | 290   if self.closed then | 
| bsw@1045 | 291     return _("#{closed_ago} ago", { closed_ago = self.closed_ago }) | 
| bsw@1045 | 292   elseif string.sub(self.state_time_left, 1, 2) ~= "-" then | 
| bsw@1045 | 293     return _("ends soon", { state_time_left = self.state_time_left }) | 
| bsw@1045 | 294   else | 
| bsw@1045 | 295     return _("ends in #{state_time_left}", { state_time_left = self.state_time_left }) | 
| bsw@1045 | 296   end | 
| bsw@1045 | 297 end |