| rev | line source | 
| bsw/jbe@0 | 1 Initiative = mondelefant.new_class() | 
| bsw/jbe@0 | 2 Initiative.table = 'initiative' | 
| bsw/jbe@0 | 3 | 
| bsw/jbe@0 | 4 Initiative:add_reference{ | 
| bsw/jbe@0 | 5   mode          = 'm1', | 
| bsw/jbe@0 | 6   to            = "Issue", | 
| bsw/jbe@0 | 7   this_key      = 'issue_id', | 
| bsw/jbe@0 | 8   that_key      = 'id', | 
| bsw/jbe@0 | 9   ref           = 'issue', | 
| bsw/jbe@0 | 10 } | 
| bsw/jbe@0 | 11 | 
| bsw/jbe@0 | 12 Initiative:add_reference{ | 
| bsw@1045 | 13   mode          = 'm1', | 
| bsw@1045 | 14   to            = "Member", | 
| bsw@1045 | 15   this_key      = 'revoked_by_member_id', | 
| bsw@1045 | 16   that_key      = 'id', | 
| bsw@1045 | 17   ref           = 'revoked_by_member', | 
| bsw@1045 | 18 } | 
| bsw@1045 | 19 | 
| bsw@1045 | 20 Initiative:add_reference{ | 
| bsw/jbe@0 | 21   mode          = '1m', | 
| bsw/jbe@0 | 22   to            = "Draft", | 
| bsw/jbe@0 | 23   this_key      = 'id', | 
| bsw/jbe@0 | 24   that_key      = 'initiative_id', | 
| bsw/jbe@0 | 25   ref           = 'drafts', | 
| bsw/jbe@0 | 26   back_ref      = 'initiative', | 
| bsw/jbe@19 | 27   default_order = '"id" DESC' | 
| bsw/jbe@0 | 28 } | 
| bsw/jbe@0 | 29 | 
| bsw/jbe@0 | 30 Initiative:add_reference{ | 
| bsw/jbe@0 | 31   mode          = '1m', | 
| bsw/jbe@0 | 32   to            = "Suggestion", | 
| bsw/jbe@0 | 33   this_key      = 'id', | 
| bsw/jbe@0 | 34   that_key      = 'initiative_id', | 
| bsw/jbe@0 | 35   ref           = 'suggestions', | 
| bsw/jbe@0 | 36   back_ref      = 'initiative', | 
| bsw@1045 | 37   default_order = '"proportional_order" NULLS LAST, id' | 
| bsw/jbe@0 | 38 } | 
| bsw/jbe@0 | 39 | 
| bsw/jbe@0 | 40 Initiative:add_reference{ | 
| bsw/jbe@0 | 41   mode          = '1m', | 
| bsw/jbe@0 | 42   to            = "Initiator", | 
| bsw/jbe@0 | 43   this_key      = 'id', | 
| bsw/jbe@0 | 44   that_key      = 'initiative_id', | 
| bsw/jbe@0 | 45   ref           = 'initiators', | 
| bsw@10 | 46   back_ref      = 'initiative' | 
| bsw/jbe@0 | 47 } | 
| bsw/jbe@0 | 48 | 
| bsw/jbe@0 | 49 Initiative:add_reference{ | 
| bsw/jbe@0 | 50   mode          = '1m', | 
| bsw/jbe@0 | 51   to            = "Supporter", | 
| bsw/jbe@0 | 52   this_key      = 'id', | 
| bsw/jbe@0 | 53   that_key      = 'initiative_id', | 
| bsw/jbe@0 | 54   ref           = 'supporters', | 
| bsw/jbe@0 | 55   back_ref      = 'initiative', | 
| bsw/jbe@0 | 56   default_order = '"id"' | 
| bsw/jbe@0 | 57 } | 
| bsw/jbe@0 | 58 | 
| bsw/jbe@0 | 59 Initiative:add_reference{ | 
| bsw/jbe@0 | 60   mode          = '1m', | 
| bsw/jbe@0 | 61   to            = "Opinion", | 
| bsw/jbe@0 | 62   this_key      = 'id', | 
| bsw/jbe@0 | 63   that_key      = 'initiative_id', | 
| bsw/jbe@0 | 64   ref           = 'opinions', | 
| bsw/jbe@0 | 65   back_ref      = 'initiative', | 
| bsw/jbe@0 | 66   default_order = '"id"' | 
| bsw/jbe@0 | 67 } | 
| bsw/jbe@0 | 68 | 
| bsw/jbe@0 | 69 Initiative:add_reference{ | 
| bsw/jbe@0 | 70   mode          = '1m', | 
| bsw/jbe@0 | 71   to            = "Vote", | 
| bsw/jbe@0 | 72   this_key      = 'id', | 
| bsw/jbe@0 | 73   that_key      = 'initiative_id', | 
| bsw/jbe@0 | 74   ref           = 'votes', | 
| bsw/jbe@0 | 75   back_ref      = 'initiative', | 
| bsw/jbe@0 | 76   default_order = '"member_id"' | 
| bsw/jbe@0 | 77 } | 
| bsw/jbe@0 | 78 | 
| bsw/jbe@0 | 79 Initiative:add_reference{ | 
| bsw@10 | 80   mode          = 'm1', | 
| bsw@10 | 81   to            = "Initiative", | 
| bsw@10 | 82   this_key      = 'suggested_initiative_id', | 
| bsw@10 | 83   that_key      = 'id', | 
| bsw@10 | 84   ref           = 'suggested_initiative', | 
| bsw@10 | 85 } | 
| bsw@10 | 86 | 
| bsw@10 | 87 Initiative:add_reference{ | 
| bsw/jbe@0 | 88   mode                  = 'mm', | 
| bsw/jbe@0 | 89   to                    = "Member", | 
| bsw/jbe@0 | 90   this_key              = 'id', | 
| bsw/jbe@0 | 91   that_key              = 'id', | 
| bsw/jbe@0 | 92   connected_by_table    = '"initiator"', | 
| bsw/jbe@0 | 93   connected_by_this_key = 'initiative_id', | 
| bsw/jbe@0 | 94   connected_by_that_key = 'member_id', | 
| bsw/jbe@0 | 95   ref                   = 'initiating_members' | 
| bsw/jbe@0 | 96 } | 
| bsw/jbe@0 | 97 | 
| bsw/jbe@0 | 98 Initiative:add_reference{ | 
| bsw/jbe@0 | 99   mode                  = 'mm', | 
| bsw/jbe@0 | 100   to                    = "Member", | 
| bsw/jbe@0 | 101   this_key              = 'id', | 
| bsw/jbe@0 | 102   that_key              = 'id', | 
| bsw/jbe@0 | 103   connected_by_table    = '"supporter"', | 
| bsw/jbe@0 | 104   connected_by_this_key = 'initiative_id', | 
| bsw/jbe@0 | 105   connected_by_that_key = 'member_id', | 
| bsw/jbe@0 | 106   ref                   = 'supporting_members' | 
| bsw/jbe@0 | 107 } | 
| bsw/jbe@0 | 108 | 
| bsw@3 | 109 Initiative:add_reference{ | 
| bsw@3 | 110   mode                  = 'mm', | 
| bsw@3 | 111   to                    = "Member", | 
| bsw@3 | 112   this_key              = 'id', | 
| bsw@3 | 113   that_key              = 'id', | 
| bsw@3 | 114   connected_by_table    = 'direct_supporter_snapshot', | 
| bsw@3 | 115   connected_by_this_key = 'initiative_id', | 
| bsw@3 | 116   connected_by_that_key = 'member_id', | 
| bsw@3 | 117   ref                   = 'supporting_members_snapshot' | 
| bsw@3 | 118 } | 
| bsw@3 | 119 | 
| bsw@551 | 120 Initiative:add_reference{ | 
| bsw@551 | 121   mode               = "11", | 
| bsw@551 | 122   to                 = mondelefant.class_prototype, | 
| bsw@551 | 123   this_key           = "id", | 
| bsw@551 | 124   that_key           = "initiative_id", | 
| bsw@551 | 125   ref                = "member_info", | 
| bsw@551 | 126   back_ref           = "initiative", | 
| bsw@551 | 127   selector_generator = function(list, options) | 
| bsw@551 | 128     assert(options.member_id, "member_id mandatory for member_info") | 
| bsw@551 | 129     local ids = { sep = ", " } | 
| bsw@551 | 130     local issue_ids = { sep = ", " } | 
| bsw@551 | 131     for i, object in ipairs(list) do | 
| bsw@551 | 132       local id = object.id | 
| bsw@551 | 133       if id ~= nil then | 
| bsw@551 | 134         ids[#ids+1] = {"?", id} | 
| bsw@551 | 135         issue_ids[#issue_ids+1] = { "?", object.issue_id } | 
| bsw@551 | 136       end | 
| bsw@551 | 137     end | 
| bsw@551 | 138 | 
| bsw@551 | 139     local sub_selector = Issue:get_db_conn():new_selector() | 
| bsw@551 | 140     if #ids == 0 then | 
| bsw@551 | 141       return sub_selector:empty_list_mode() | 
| bsw@551 | 142     end | 
| bsw@551 | 143     sub_selector:from("issue") | 
| bsw@551 | 144     sub_selector:add_field("issue.id", "issue_id") | 
| bsw@551 | 145     sub_selector:add_field{ '(delegation_info(?, null, null, issue.id, ?)).*', options.member_id, options.trustee_id } | 
| bsw@551 | 146     sub_selector:add_where{ 'issue.id IN ($)', issue_ids } | 
| bsw@551 | 147 | 
| bsw@551 | 148     local selector = Initiative:get_db_conn():new_selector() | 
| bsw@551 | 149     selector:add_from("initiative") | 
| bsw@551 | 150     selector:add_field("initiative.id", "initiative_id") | 
| bsw@551 | 151     selector:join("issue", nil, "issue.id = initiative.issue_id") | 
| bsw@551 | 152     selector:join(sub_selector, "delegation_info", "delegation_info.issue_id = issue.id") | 
| bsw@551 | 153     selector:add_field("delegation_info.*") | 
| bsw@551 | 154 | 
| bsw@551 | 155     selector:left_join("supporter", nil, "supporter.initiative_id = initiative.id AND supporter.member_id = delegation_info.participating_member_id") | 
| bsw@551 | 156 | 
| bsw/jbe@1309 | 157     selector:left_join("delegating_interest_snapshot", "delegating_interest_s", { "delegating_interest_s.snapshot_id = issue.latest_snapshot_id AND delegating_interest_s.issue_id = issue.id AND delegating_interest_s.member_id = ?", options.member_id }) | 
| bsw@551 | 158 | 
| bsw/jbe@1309 | 159     selector:left_join("direct_supporter_snapshot", "supporter_s", { "supporter_s.snapshot_id = issue.latest_snapshot_id AND supporter_s.initiative_id = initiative.id AND (supporter_s.member_id = ? OR supporter_s.member_id = delegating_interest_s.delegate_member_ids[array_upper(delegating_interest_s.delegate_member_ids, 1)])", options.member_id }) | 
| bsw@551 | 160 | 
| bsw@551 | 161     selector:add_field("CASE WHEN issue.fully_frozen ISNULL AND issue.closed ISNULL THEN supporter.member_id NOTNULL ELSE supporter_s.member_id NOTNULL END", "supported") | 
| bsw@551 | 162     selector:add_field({ "CASE WHEN issue.fully_frozen ISNULL AND issue.closed ISNULL THEN delegation_info.own_participation AND supporter.member_id NOTNULL ELSE supporter_s.member_id = ? END", options.member_id }, "directly_supported") | 
| bsw@551 | 163 | 
| bsw@551 | 164     selector:add_field("CASE WHEN issue.fully_frozen ISNULL AND issue.closed ISNULL THEN supporter.member_id NOTNULL AND NOT EXISTS(SELECT 1 FROM critical_opinion WHERE critical_opinion.initiative_id = initiative.id AND critical_opinion.member_id = delegation_info.participating_member_id) ELSE supporter_s.satisfied NOTNULL END", "satisfied") | 
| bsw@551 | 165 | 
| bsw@551 | 166 | 
| bsw@551 | 167     --selector:add_field("", "informed") | 
| bsw@551 | 168     selector:left_join("initiator", nil, { "initiator.initiative_id = initiative.id AND initiator.member_id = ? AND initiator.accepted", options.member_id }) | 
| bsw@551 | 169     selector:add_field("initiator.member_id NOTNULL", "initiated") | 
| bsw@551 | 170 | 
| bsw@551 | 171     return selector | 
| bsw@551 | 172   end | 
| bsw@551 | 173 } | 
| bsw@551 | 174 | 
| bsw@551 | 175 function Initiative.list:load_everything_for_member_id(member_id) | 
| 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 end | 
| bsw@551 | 180 | 
| bsw@551 | 181 function Initiative.object:load_everything_for_member_id(member_id) | 
| bsw@551 | 182   if member_id then | 
| bsw@551 | 183     self:load("member_info", { member_id = member_id }) | 
| bsw@551 | 184   end | 
| bsw@551 | 185 end | 
| bsw@551 | 186 | 
| bsw@558 | 187 function Initiative:selector_for_updated_drafts(member_id) | 
| bsw@558 | 188   return Initiative:new_selector() | 
| bsw@558 | 189     :join("issue", "_issue_state", "_issue_state.id = initiative.issue_id AND _issue_state.closed ISNULL AND _issue_state.fully_frozen ISNULL") | 
| bsw@558 | 190     :join("current_draft", "_current_draft", "_current_draft.initiative_id = initiative.id") | 
| bsw@558 | 191     :join("supporter", "supporter", { "supporter.member_id = ? AND supporter.initiative_id = initiative.id AND supporter.draft_id < _current_draft.id", member_id }) | 
| bsw@558 | 192     :add_where("initiative.revoked ISNULL") | 
| bsw@558 | 193 end | 
| bsw@2 | 194 | 
| bsw@1045 | 195 function Initiative:getSpecialSelector( args ) | 
| bsw@1045 | 196   local selector = Initiative:new_selector() | 
| bsw@1045 | 197   selector:join( "issue", nil, "issue.id = initiative.issue_id" ) | 
| bsw@1045 | 198   selector:join( "area", nil, "area.id = issue.area_id" ) | 
| bsw@1045 | 199   if args.area_id then | 
| bsw@1045 | 200     selector:add_where{ "area.id = ?", args.area_id } | 
| bsw@1045 | 201   elseif args.unit_id then | 
| bsw@1045 | 202     selector:add_where{ "area.unit_id = ?", args.unit_id } | 
| bsw@1045 | 203   end | 
| bsw@1045 | 204   selector:limit( 1 ) | 
| bsw@1045 | 205   selector:optional_object_mode() | 
| bsw@1045 | 206   return selector | 
| bsw@1045 | 207 end | 
| bsw@1045 | 208 | 
| bsw@1045 | 209 function Initiative:getLastWinner( args ) | 
| bsw@1045 | 210   local selector = Initiative:getSpecialSelector( args ) | 
| bsw@1045 | 211   selector:add_where( "issue.state = 'finished_with_winner'" ) | 
| bsw@1045 | 212   selector:add_order_by( "issue.closed DESC, id DESC" ) | 
| bsw@1045 | 213   return selector:exec() | 
| bsw@1045 | 214 end | 
| bsw@1045 | 215 | 
| bsw@1045 | 216 function Initiative:getLastLoser( args ) | 
| bsw@1045 | 217   local selector = Initiative:getSpecialSelector( args ) | 
| bsw@1045 | 218   selector:add_where( "issue.state = 'finished_without_winner'" ) | 
| bsw@1045 | 219   selector:add_order_by( "issue.closed DESC, id DESC" ) | 
| bsw@1045 | 220   return selector:exec() | 
| bsw@1045 | 221 end | 
| bsw@1045 | 222 | 
| bsw@1045 | 223 function Initiative:getNextEndingVoting( args ) | 
| bsw@1045 | 224   local selector = Initiative:getSpecialSelector( args ) | 
| bsw@1045 | 225   selector:add_where( "issue.state = 'voting'" ) | 
| bsw@1045 | 226   selector:add_order_by( "issue.fully_frozen + issue.verification_time DESC, id DESC" ) | 
| bsw@1045 | 227   return selector:exec() | 
| bsw@1045 | 228 end | 
| bsw@1045 | 229 | 
| bsw@1045 | 230 function Initiative:getNextEndingVerification( args ) | 
| bsw@1045 | 231   local selector = Initiative:getSpecialSelector( args ) | 
| bsw@1045 | 232   selector:add_where( "issue.state = 'verification'" ) | 
| bsw@1045 | 233   selector:add_order_by( "issue.half_frozen + issue.verification_time DESC, id DESC" ) | 
| bsw@1045 | 234   return selector:exec() | 
| bsw@1045 | 235 end | 
| bsw@1045 | 236 | 
| bsw@1045 | 237 function Initiative:getNextEndingDiscussion( args ) | 
| bsw@1045 | 238   local selector = Initiative:getSpecialSelector( args ) | 
| bsw@1045 | 239   selector:add_where( "issue.state = 'discussion'" ) | 
| bsw@1045 | 240   selector:add_order_by( "issue.accepted + issue.discussion_time DESC, id DESC" ) | 
| bsw@1045 | 241   return selector:exec() | 
| bsw@1045 | 242 end | 
| bsw@1045 | 243 | 
| bsw@1045 | 244 function Initiative:getBestInAdmission( args ) | 
| bsw@1045 | 245   local selector = Initiative:getSpecialSelector( args ) | 
| bsw@1045 | 246   selector:add_where( "issue.state = 'admission'" ) | 
| bsw@1234 | 247   selector:add_order_by( "issue.created + issue.max_admission_time DESC, id DESC" ) | 
| bsw@1045 | 248   return selector:exec() | 
| bsw@1045 | 249 end | 
| bsw@2 | 250 | 
| bsw/jbe@0 | 251 function Initiative.object_get:current_draft() | 
| bsw/jbe@0 | 252   return Draft:new_selector() | 
| bsw/jbe@0 | 253     :add_where{ '"initiative_id" = ?', self.id } | 
| bsw/jbe@0 | 254     :add_order_by('"id" DESC') | 
| bsw/jbe@0 | 255     :single_object_mode() | 
| bsw/jbe@0 | 256     :exec() | 
| bsw/jbe@0 | 257 end | 
| bsw/jbe@0 | 258 | 
| bsw/jbe@0 | 259 function Initiative.object_get:shortened_name() | 
| bsw/jbe@0 | 260   local name = self.name | 
| bsw/jbe@0 | 261   if #name > 100 then | 
| bsw/jbe@0 | 262     name = name:sub(1,100) .. "..." | 
| bsw/jbe@0 | 263   end | 
| bsw/jbe@0 | 264   return name | 
| bsw/jbe@0 | 265 end | 
| bsw/jbe@52 | 266 | 
| bsw@1045 | 267 function Initiative.object_get:display_name() | 
| bsw@1045 | 268   return "i" .. self.id .. ": " .. self.name | 
| bsw@1045 | 269 end | 
| bsw@1045 | 270 | 
| bsw/jbe@52 | 271 function Initiative.object_get:initiator_names() | 
| bsw/jbe@52 | 272   local members = Member:new_selector() | 
| bsw/jbe@52 | 273     :join("initiator", nil, "initiator.member_id = member.id") | 
| bsw/jbe@52 | 274     :add_where{ "initiator.initiative_id = ?", self.id } | 
| bsw/jbe@52 | 275     :add_where{ "initiator.accepted" } | 
| bsw/jbe@52 | 276     :exec() | 
| bsw/jbe@52 | 277 | 
| bsw/jbe@52 | 278   local member_names = {} | 
| bsw/jbe@52 | 279   for i, member in ipairs(members) do | 
| bsw/jbe@52 | 280     member_names[#member_names+1] = member.name | 
| bsw/jbe@52 | 281   end | 
| bsw/jbe@52 | 282   return member_names | 
| bsw/jbe@52 | 283 end | 
| bsw/jbe@52 | 284 | 
| bsw@1045 | 285 function Initiative.object_get:potential_supporter_count() | 
| bsw@1045 | 286   if self.supporter_count and self.satisfied_supporter_count then | 
| bsw@1045 | 287     return self.supporter_count - self.satisfied_supporter_count | 
| bsw@1045 | 288   end | 
| bsw@1045 | 289 end |