| rev | line source | 
| bsw@2 | 1 local old_draft_id = param.get("old_draft_id", atom.integer) | 
| bsw@2 | 2 local new_draft_id = param.get("new_draft_id", atom.integer) | 
| bsw@1045 | 3 local initiative_id = param.get("initiative_id", atom.number) | 
| bsw@2 | 4 | 
| bsw@1045 | 5 if not old_draft_id | 
| bsw@1045 | 6   or not new_draft_id | 
| bsw@1045 | 7   or old_draft_id == new_draft_id | 
| bsw@1045 | 8 then | 
| bsw@1045 | 9   slot.reset_all() | 
| bsw@1045 | 10   slot.select("error", function() | 
| bsw@1045 | 11     ui.tag{ content = _"Please choose two different versions of the draft to compare" } | 
| bsw@1045 | 12   end ) | 
| bsw@1045 | 13   request.redirect{ | 
| bsw@1489 | 14     module = "initiative", view = "history", id = initiative_id | 
| bsw@1045 | 15   } | 
| bsw@10 | 16   return | 
| bsw@10 | 17 end | 
| bsw@10 | 18 | 
| bsw@2 | 19 if old_draft_id > new_draft_id then | 
| jbe@1226 | 20   old_draft_id, new_draft_id = new_draft_id, old_draft_id | 
| bsw@2 | 21 end | 
| bsw@2 | 22 | 
| bsw@2 | 23 local old_draft = Draft:by_id(old_draft_id) | 
| bsw@2 | 24 local new_draft = Draft:by_id(new_draft_id) | 
| bsw@2 | 25 | 
| bsw@1045 | 26 local initiative = new_draft.initiative | 
| bsw@1045 | 27 | 
| bsw@1045 | 28 if app.session.member then | 
| bsw@1045 | 29   initiative:load_everything_for_member_id(app.session.member_id) | 
| bsw@1045 | 30   initiative.issue:load_everything_for_member_id(app.session.member_id) | 
| bsw@1045 | 31 end | 
| bsw@1045 | 32 | 
| bsw@1045 | 33 | 
| bsw/jbe@1309 | 34 local old_draft_content = string.gsub(string.gsub(util.html_to_text(old_draft.content), "\n", " ###ENTER###\n"), " ", "\n") | 
| bsw/jbe@1309 | 35 local new_draft_content = string.gsub(string.gsub(util.html_to_text(new_draft.content), "\n", " ###ENTER###\n"), " ", "\n") | 
| bsw@95 | 36 | 
| jbe@1226 | 37 local key = multirand.string(24, "0123456789abcdefghijklmnopqrstuvwxyz") | 
| bsw@2 | 38 | 
| bsw@1230 | 39 local old_draft_filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "diff-" .. key .. "-old.tmp") | 
| bsw@1230 | 40 local new_draft_filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "diff-" .. key .. "-new.tmp") | 
| bsw@2 | 41 | 
| bsw@2 | 42 local old_draft_file = assert(io.open(old_draft_filename, "w")) | 
| bsw@95 | 43 old_draft_file:write(old_draft_content) | 
| bsw@2 | 44 old_draft_file:write("\n") | 
| bsw@2 | 45 old_draft_file:close() | 
| bsw@2 | 46 | 
| bsw@2 | 47 local new_draft_file = assert(io.open(new_draft_filename, "w")) | 
| bsw@95 | 48 new_draft_file:write(new_draft_content) | 
| bsw@2 | 49 new_draft_file:write("\n") | 
| bsw@2 | 50 new_draft_file:close() | 
| bsw@2 | 51 | 
| bsw/jbe@1309 | 52 local output, err, status = extos.pfilter(nil, "sh", "-c", "diff -a -U 1000000000 '" .. old_draft_filename .. "' '" .. new_draft_filename .. "' | grep --binary-files=text -v ^--- | grep --binary-files=text -v ^+++ | grep --binary-files=text -v ^@") | 
| bsw@2 | 53 | 
| bsw@2 | 54 os.remove(old_draft_filename) | 
| bsw@2 | 55 os.remove(new_draft_filename) | 
| bsw@2 | 56 | 
| bsw@95 | 57 local last_state = "first_run" | 
| bsw@95 | 58 | 
| bsw@95 | 59 local function process_line(line) | 
| bsw@95 | 60   local state_char = string.sub(line, 1, 1) | 
| bsw@95 | 61   local state | 
| bsw@95 | 62   if state_char == "+" then | 
| bsw@95 | 63     state = "added" | 
| bsw@95 | 64   elseif state_char == "-" then | 
| bsw@95 | 65     state = "removed" | 
| bsw@95 | 66   elseif state_char == " " then | 
| bsw@95 | 67     state = "unchanged" | 
| bsw@95 | 68   end | 
| bsw@95 | 69   local state_changed = false | 
| bsw@95 | 70   if state ~= last_state then | 
| bsw@95 | 71     if last_state ~= "first_run" then | 
| bsw@95 | 72       slot.put("</span> ") | 
| bsw@95 | 73     end | 
| bsw@95 | 74     last_state = state | 
| bsw@95 | 75     state_changed = true | 
| bsw@95 | 76     slot.put("<span class=\"diff_" .. tostring(state) .. "\">") | 
| bsw@95 | 77   end | 
| bsw@95 | 78 | 
| bsw@95 | 79   line = string.sub(line, 2, #line) | 
| bsw@95 | 80   if line ~= "###ENTER###" then | 
| bsw@95 | 81     if not state_changed then | 
| bsw@95 | 82       slot.put(" ") | 
| bsw@95 | 83     end | 
| bsw/jbe@1309 | 84     --slot.put(encode.html(line)) | 
| bsw/jbe@1309 | 85     slot.put(line) | 
| bsw@95 | 86   else | 
| bsw@95 | 87     slot.put("<br />") | 
| bsw@95 | 88   end | 
| bsw@95 | 89 end | 
| bsw@95 | 90 | 
| bsw/jbe@1309 | 91 execute.view{ module = "issue", view = "_head", params = { issue = initiative.issue } } | 
| bsw/jbe@1309 | 92 | 
| bsw/jbe@1309 | 93 ui.grid{ content = function() | 
| bsw/jbe@1309 | 94   ui.cell_main{ content = function() | 
| bsw/jbe@1309 | 95     ui.container{ attr = { class = "mdl-card mdl-card__fullwidth mdl-shadow--2dp" }, content = function() | 
| bsw/jbe@1309 | 96 | 
| bsw/jbe@1309 | 97       ui.container{ attr = { class = "mdl-card__title mdl-card--border" }, content = function () | 
| bsw@1045 | 98         ui.heading { | 
| bsw/jbe@1309 | 99           attr = { class = "mdl-card__title-text" }, | 
| bsw/jbe@1309 | 100           content = function() | 
| bsw/jbe@1309 | 101             ui.link{ | 
| bsw/jbe@1309 | 102               module = "initiative", view = "show", id = initiative.id, | 
| bsw/jbe@1309 | 103               content = initiative.display_name | 
| bsw/jbe@1309 | 104             } | 
| bsw/jbe@1309 | 105           end | 
| bsw@1045 | 106         } | 
| bsw/jbe@1309 | 107         ui.container{ content = _("Comparision of revisions #{id1} and #{id2}", { | 
| bsw/jbe@1309 | 108           id1 = old_draft.id, | 
| bsw/jbe@1309 | 109           id2 = new_draft.id | 
| bsw/jbe@1309 | 110         } ) } | 
| bsw/jbe@1309 | 111       end } | 
| bsw/jbe@1309 | 112 | 
| bsw/jbe@1309 | 113       if app.session.member_id and not new_draft.initiative.revoked then | 
| bsw/jbe@1309 | 114         local supporter = app.session.member:get_reference_selector("supporters") | 
| bsw/jbe@1309 | 115           :add_where{ "initiative_id = ?", new_draft.initiative_id } | 
| bsw/jbe@1309 | 116           :optional_object_mode() | 
| bsw/jbe@1309 | 117           :exec() | 
| bsw/jbe@1309 | 118         if supporter and supporter.draft_id == old_draft.id and new_draft.id == initiative.current_draft.id then | 
| bsw/jbe@1309 | 119           ui.container { | 
| bsw/jbe@1309 | 120             attr = { class = "mdl-card__content mdl-card--no-bottom-pad mdl-card--notice" }, | 
| bsw/jbe@1309 | 121             content = _"The draft of this initiative has been updated!" | 
| bsw@1045 | 122           } | 
| bsw/jbe@1309 | 123           ui.container { | 
| bsw/jbe@1309 | 124             attr = { class = "mdl-card__actions mdl-card--action-border  mdl-card--notice" }, | 
| bsw/jbe@1309 | 125             content = function () | 
| bsw/jbe@1309 | 126               ui.link{ | 
| bsw/jbe@1309 | 127                 attr = { class = "mdl-button mdl-js-button mdl-button--raised" }, | 
| bsw/jbe@1309 | 128                 text   = _"refresh my support", | 
| bsw/jbe@1309 | 129                 module = "initiative", | 
| bsw/jbe@1309 | 130                 action = "add_support", | 
| bsw/jbe@1309 | 131                 id     = new_draft.initiative.id, | 
| bsw/jbe@1309 | 132                 params = { draft_id = new_draft.id }, | 
| bsw/jbe@1309 | 133                 routing = { | 
| bsw/jbe@1309 | 134                   default = { | 
| bsw/jbe@1309 | 135                     mode = "redirect", | 
| bsw/jbe@1309 | 136                     module = "initiative", | 
| bsw/jbe@1309 | 137                     view = "show", | 
| bsw/jbe@1309 | 138                     id = new_draft.initiative.id | 
| bsw/jbe@1309 | 139                   } | 
| bsw/jbe@1309 | 140                 } | 
| bsw/jbe@1309 | 141               } | 
| bsw@1045 | 142 | 
| bsw/jbe@1309 | 143               slot.put("   ") | 
| bsw/jbe@1309 | 144 | 
| bsw/jbe@1309 | 145               ui.link{ | 
| bsw/jbe@1309 | 146                 attr = { class = "mdl-button mdl-js-button mdl-button--raised" }, | 
| bsw/jbe@1309 | 147                 text   = _"remove my support", | 
| bsw/jbe@1309 | 148                 module = "initiative", | 
| bsw/jbe@1309 | 149                 action = "remove_support", | 
| bsw/jbe@1309 | 150                 id     = new_draft.initiative.id, | 
| bsw/jbe@1309 | 151                 routing = { | 
| bsw/jbe@1309 | 152                   default = { | 
| bsw/jbe@1309 | 153                     mode = "redirect", | 
| bsw/jbe@1309 | 154                     module = "initiative", | 
| bsw/jbe@1309 | 155                     view = "show", | 
| bsw/jbe@1309 | 156                     id = new_draft.initiative.id | 
| bsw/jbe@1309 | 157                   } | 
| bsw/jbe@1309 | 158                 } | 
| bsw/jbe@1309 | 159               } | 
| bsw/jbe@1309 | 160 | 
| bsw/jbe@1309 | 161               slot.put("   ") | 
| bsw/jbe@1309 | 162 | 
| bsw/jbe@1309 | 163               ui.link{ | 
| bsw/jbe@1309 | 164                 attr = { class = "mdl-button mdl-js-button" }, | 
| bsw/jbe@1309 | 165                 text   = _"cancel", | 
| bsw/jbe@1309 | 166                 module = "initiative", | 
| bsw/jbe@1309 | 167                 view   = "show", | 
| bsw/jbe@1309 | 168                 id     = new_draft.initiative.id, | 
| bsw/jbe@1309 | 169               } | 
| bsw/jbe@1309 | 170             end | 
| bsw@1045 | 171           } | 
| bsw/jbe@1309 | 172         end | 
| bsw/jbe@1309 | 173       end | 
| bsw@2 | 174 | 
| bsw/jbe@1309 | 175       ui.container { | 
| bsw/jbe@1309 | 176         attr = { class = "draft mdl-card__content mdl-card--border" }, | 
| bsw/jbe@1309 | 177         content = function () | 
| bsw/jbe@1309 | 178           if not status then | 
| bsw/jbe@1309 | 179             ui.field.text{ value = _"The drafts do not differ" } | 
| bsw/jbe@1309 | 180           else | 
| bsw/jbe@1309 | 181             ui.container{ | 
| bsw/jbe@1309 | 182               tag = "div", | 
| bsw/jbe@1309 | 183               attr = { class = "diff" }, | 
| bsw/jbe@1309 | 184               content = function() | 
| bsw/jbe@1309 | 185                 output = output:gsub("[^\n\r]+", function(line) | 
| bsw/jbe@1309 | 186                   process_line(line) | 
| bsw/jbe@1309 | 187                 end) | 
| bsw/jbe@1309 | 188               end | 
| bsw/jbe@1309 | 189             } | 
| bsw/jbe@1309 | 190           end | 
| bsw@1045 | 191         end | 
| bsw@1045 | 192       } | 
| bsw@1496 | 193 | 
| bsw@1496 | 194       local old_files = File:new_selector() | 
| bsw@1496 | 195         :left_join("draft_attachment", nil, "draft_attachment.file_id = file.id") | 
| bsw@1496 | 196         :add_where{ "draft_attachment.draft_id = ?", old_draft.id } | 
| bsw@1496 | 197         :reset_fields() | 
| bsw@1496 | 198         :add_field("file.id") | 
| bsw@1496 | 199         :add_field("draft_attachment.title") | 
| bsw@1496 | 200         :add_field("draft_attachment.description") | 
| bsw@1496 | 201         :add_order_by("draft_attachment.id") | 
| bsw@1496 | 202         :exec() | 
| bsw@1496 | 203 | 
| bsw@1496 | 204       local new_files = File:new_selector() | 
| bsw@1496 | 205         :left_join("draft_attachment", nil, "draft_attachment.file_id = file.id") | 
| bsw@1496 | 206         :add_where{ "draft_attachment.draft_id = ?", new_draft.id } | 
| bsw@1496 | 207         :reset_fields() | 
| bsw@1496 | 208         :add_field("file.id") | 
| bsw@1496 | 209         :add_field("draft_attachment.title") | 
| bsw@1496 | 210         :add_field("draft_attachment.description") | 
| bsw@1496 | 211         :add_order_by("draft_attachment.id") | 
| bsw@1496 | 212         :exec() | 
| bsw@1496 | 213 | 
| bsw@1496 | 214       local added_files = {} | 
| bsw@1496 | 215       for i, new_file in ipairs(new_files) do | 
| bsw@1496 | 216         local added = true | 
| bsw@1496 | 217         for j, old_file in ipairs(old_files) do | 
| bsw@1496 | 218           if | 
| bsw@1496 | 219             old_file.file_id == new_file.file_id | 
| bsw@1496 | 220             and old_file.title == new_file.title | 
| bsw@1496 | 221             and old_file.description == new_file.description | 
| bsw@1496 | 222           then | 
| bsw@1496 | 223             added = false | 
| bsw@1496 | 224           end | 
| bsw@1496 | 225         end | 
| bsw@1496 | 226         if added then | 
| bsw@1496 | 227           table.insert(added_files, new_file) | 
| bsw@1496 | 228         end | 
| bsw@1496 | 229       end | 
| bsw@1496 | 230 | 
| bsw@1496 | 231       if #added_files > 0 then | 
| bsw@1496 | 232         ui.container { | 
| bsw@1496 | 233           attr = { class = "mdl-card__content mdl-card--border" }, | 
| bsw@1496 | 234           content = function() | 
| bsw@1496 | 235             ui.container{ content = _"Added attachments" } | 
| bsw@1496 | 236             for i, file in ipairs(added_files) do | 
| bsw@1496 | 237               ui.image{ module = "file", view = "show.jpg", id = file.id, params = { preview = true } } | 
| bsw@1496 | 238               ui.container{ content = file.title or "" } | 
| bsw@1496 | 239               ui.container{ content = file.description or "" } | 
| bsw@1496 | 240               slot.put("<br /><br />") | 
| bsw@1496 | 241             end | 
| bsw@1496 | 242           end | 
| bsw@1496 | 243         } | 
| bsw@1496 | 244       end | 
| bsw@1496 | 245 | 
| bsw@1496 | 246       local removed_files = {} | 
| bsw@1496 | 247       for i, old_file in ipairs(old_files) do | 
| bsw@1496 | 248         local removed = true | 
| bsw@1496 | 249         for j, new_file in ipairs(new_files) do | 
| bsw@1496 | 250           if | 
| bsw@1496 | 251             old_file.file_id == new_file.file_id | 
| bsw@1496 | 252             and old_file.title == new_file.title | 
| bsw@1496 | 253             and old_file.description == new_file.description | 
| bsw@1496 | 254           then | 
| bsw@1496 | 255             removed = false | 
| bsw@1496 | 256           end | 
| bsw@1496 | 257         end | 
| bsw@1496 | 258         if removed then | 
| bsw@1496 | 259           table.insert(removed_files, old_file) | 
| bsw@1496 | 260         end | 
| bsw@1496 | 261       end | 
| bsw@1496 | 262 | 
| bsw@1496 | 263 | 
| bsw@1496 | 264       if #removed_files > 0 then | 
| bsw@1496 | 265         ui.container { | 
| bsw@1496 | 266           attr = { class = "mdl-card__content mdl-card--border" }, | 
| bsw@1496 | 267           content = function() | 
| bsw@1496 | 268             ui.container{ content = _"Removed attachments" } | 
| bsw@1496 | 269             for i, file in ipairs(removed_files) do | 
| bsw@1496 | 270               ui.image{ module = "file", view = "show.jpg", id = file.id, params = { preview = true } } | 
| bsw@1496 | 271               ui.container{ content = file.title or "" } | 
| bsw@1496 | 272               ui.container{ content = file.description or "" } | 
| bsw@1496 | 273               slot.put("<br /><br />") | 
| bsw@1496 | 274             end | 
| bsw@1496 | 275           end | 
| bsw@1496 | 276         } | 
| bsw@1496 | 277       end | 
| bsw@1496 | 278 | 
| bsw@1496 | 279       ui.container { | 
| bsw@1496 | 280         attr = { class = "draft mdl-card__content mdl-card--border" }, | 
| bsw@1496 | 281         content = function () | 
| bsw@1496 | 282         end | 
| bsw@1496 | 283       } | 
| bsw@1496 | 284 | 
| bsw/jbe@1309 | 285     end } | 
| bsw/jbe@1309 | 286   end } | 
| bsw/jbe@1309 | 287   ui.cell_sidebar{ content = function() | 
| bsw/jbe@1309 | 288 | 
| bsw/jbe@1309 | 289     execute.view{ module = "issue", view = "_sidebar", params = { | 
| bsw/jbe@1309 | 290       initiative = initiative, | 
| bsw/jbe@1309 | 291       issue = initiative.issue | 
| bsw/jbe@1309 | 292     } } | 
| bsw@1045 | 293 | 
| bsw/jbe@1309 | 294     execute.view { | 
| bsw/jbe@1309 | 295       module = "issue", view = "_sidebar_whatcanido", | 
| bsw/jbe@1309 | 296       params = { initiative = initiative } | 
| bsw/jbe@1309 | 297     } | 
| bsw/jbe@1309 | 298 | 
| bsw/jbe@1309 | 299     execute.view { | 
| bsw/jbe@1309 | 300       module = "issue", view = "_sidebar_members", params = { | 
| bsw/jbe@1309 | 301         issue = initiative.issue, initiative = initiative | 
| bsw/jbe@1309 | 302       } | 
| bsw/jbe@1309 | 303     } | 
| bsw/jbe@1309 | 304   end } | 
| bsw/jbe@1309 | 305 end } |