liquid_feedback_frontend
diff app/main/draft/_action/add.lua @ 1496:ed3c40911ae1
Completed image attachments feature
| author | bsw |
|---|---|
| date | Tue Feb 11 15:24:36 2020 +0100 (2020-02-11) |
| parents | 17e7082c377a |
| children | 770ab0a7f79b |
line diff
1.1 --- a/app/main/draft/_action/add.lua Mon Feb 10 21:10:49 2020 +0100 1.2 +++ b/app/main/draft/_action/add.lua Tue Feb 11 15:24:36 2020 +0100 1.3 @@ -1,24 +1,270 @@ 1.4 -local draft_text = param.get("content") 1.5 +local initiative 1.6 +local new_initiative 1.7 +local draft_id 1.8 +local status 1.9 + 1.10 +if param.get("initiative_id", atom.integer) then 1.11 + 1.12 + local function donew() 1.13 + local draft_text = param.get("content") 1.14 + 1.15 + if not draft_text then 1.16 + return false 1.17 + end 1.18 + 1.19 + local draft_text = util.wysihtml_preproc(draft_text) 1.20 + 1.21 + local valid_html, error_message = util.html_is_safe(draft_text) 1.22 + if not valid_html then 1.23 + slot.put_into("error", _("Draft contains invalid formatting or character sequence: #{error_message}", { error_message = error_message }) ) 1.24 + return false 1.25 + end 1.26 + 1.27 + if config.initiative_abstract then 1.28 + local abstract = param.get("abstract") 1.29 + if not abstract then 1.30 + return false 1.31 + end 1.32 + abstract = encode.html(abstract) 1.33 + draft_text = abstract .. "<!--END_OF_ABSTRACT-->" .. draft_text 1.34 + end 1.35 + 1.36 + draft_id = Draft:update_content( 1.37 + app.session.member.id, 1.38 + param.get("initiative_id", atom.integer), 1.39 + param.get("formatting_engine"), 1.40 + draft_text, 1.41 + nil, 1.42 + param.get("preview") or param.get("edit") 1.43 + ) 1.44 + return draft_id and true or false 1.45 + end 1.46 + 1.47 + status = donew() 1.48 + 1.49 +else 1.50 + 1.51 + local function donew() 1.52 + local issue 1.53 + local area 1.54 1.55 -if not draft_text then 1.56 - return false 1.57 -end 1.58 + local issue_id = param.get("issue_id", atom.integer) 1.59 + if issue_id then 1.60 + issue = Issue:new_selector():add_where{"id=?",issue_id}:for_share():single_object_mode():exec() 1.61 + if issue.closed then 1.62 + slot.put_into("error", _"This issue is already closed.") 1.63 + return false 1.64 + elseif issue.fully_frozen then 1.65 + slot.put_into("error", _"Voting for this issue has already begun.") 1.66 + return false 1.67 + elseif issue.phase_finished then 1.68 + slot.put_into("error", _"Current phase is already closed.") 1.69 + return false 1.70 + end 1.71 + area = issue.area 1.72 + else 1.73 + local area_id = param.get("area_id", atom.integer) 1.74 + area = Area:new_selector():add_where{"id=?",area_id}:single_object_mode():exec() 1.75 + if not area.active then 1.76 + slot.put_into("error", "Invalid area.") 1.77 + return false 1.78 + end 1.79 + end 1.80 + 1.81 + if not app.session.member:has_voting_right_for_unit_id(area.unit_id) then 1.82 + return execute.view { module = "index", view = "403" } 1.83 + end 1.84 + 1.85 + local policy_id = param.get("policy_id", atom.integer) 1.86 + local policy 1.87 + if policy_id then 1.88 + policy = Policy:by_id(policy_id) 1.89 + end 1.90 1.91 -local draft_text = util.wysihtml_preproc(draft_text) 1.92 + if not issue then 1.93 + if policy_id == -1 then 1.94 + slot.put_into("error", _"Please choose a policy") 1.95 + return false 1.96 + end 1.97 + if not policy.active then 1.98 + slot.put_into("error", "Invalid policy.") 1.99 + return false 1.100 + end 1.101 + if policy.polling and not app.session.member:has_polling_right_for_unit_id(area.unit_id) then 1.102 + return execute.view { module = "index", view = "403" } 1.103 + end 1.104 + if not area:get_reference_selector("allowed_policies") 1.105 + :add_where{ "policy.id = ?", policy_id } 1.106 + :optional_object_mode() 1.107 + :exec() 1.108 + then 1.109 + slot.put_into("error", "policy not allowed") 1.110 + return false 1.111 + end 1.112 + end 1.113 + 1.114 + local is_polling = (issue and param.get("polling", atom.boolean)) or (policy and policy.polling) or false 1.115 + 1.116 + local tmp = db:query({ "SELECT text_entries_left, initiatives_left FROM member_contingent_left WHERE member_id = ? AND polling = ?", app.session.member.id, is_polling }, "opt_object") 1.117 + if not tmp or tmp.initiatives_left < 1 then 1.118 + slot.put_into("error", _"Sorry, your contingent for creating initiatives has been used up. Please try again later.") 1.119 + return false 1.120 + end 1.121 + if tmp and tmp.text_entries_left < 1 then 1.122 + slot.put_into("error", _"Sorry, you have reached your personal flood limit. Please be slower...") 1.123 + return false 1.124 + end 1.125 + 1.126 + local name = param.get("name") 1.127 + 1.128 + local name = util.trim(name) 1.129 + 1.130 + if #name < 3 then 1.131 + slot.put_into("error", _"Please enter a meaningful title for your initiative!") 1.132 + return false 1.133 + end 1.134 + 1.135 + if #name > 140 then 1.136 + slot.put_into("error", _"This title is too long!") 1.137 + return false 1.138 + end 1.139 1.140 -local valid_html, error_message = util.html_is_safe(draft_text) 1.141 -if not valid_html then 1.142 - slot.put_into("error", _("Draft contains invalid formatting or character sequence: #{error_message}", { error_message = error_message }) ) 1.143 - return false 1.144 -end 1.145 + local timing 1.146 + if not issue and policy.free_timeable then 1.147 + local free_timing_string = util.trim(param.get("free_timing")) 1.148 + if not free_timing_string or #free_timing_string < 1 then 1.149 + slot.put_into("error", _"Choose timing") 1.150 + return false 1.151 + end 1.152 + local available_timings 1.153 + if config.free_timing and config.free_timing.available_func then 1.154 + available_timings = config.free_timing.available_func(policy) 1.155 + if available_timings == false then 1.156 + slot.put_into("error", "error in free timing config") 1.157 + return false 1.158 + end 1.159 + end 1.160 + if available_timings then 1.161 + local timing_available = false 1.162 + for i, available_timing in ipairs(available_timings) do 1.163 + if available_timing.id == free_timing_string then 1.164 + timing_available = true 1.165 + end 1.166 + end 1.167 + if not timing_available then 1.168 + slot.put_into("error", _"Invalid timing") 1.169 + return false 1.170 + end 1.171 + end 1.172 + timing = config.free_timing.calculate_func(policy, free_timing_string) 1.173 + if not timing then 1.174 + slot.put_into("error", "error in free timing config") 1.175 + return false 1.176 + end 1.177 + end 1.178 + 1.179 + local draft_text = param.get("content") 1.180 + 1.181 + if not draft_text then 1.182 + slot.put_into("error", "no draft text") 1.183 + return false 1.184 + end 1.185 + 1.186 + local draft_text = util.wysihtml_preproc(draft_text) 1.187 + 1.188 + local valid_html, error_message = util.html_is_safe(draft_text) 1.189 + if not valid_html then 1.190 + slot.put_into("error", _("Draft contains invalid formatting or character sequence: #{error_message}", { error_message = error_message }) ) 1.191 + return false 1.192 + end 1.193 + 1.194 + if config.initiative_abstract then 1.195 + local abstract = param.get("abstract") 1.196 + if not abstract then 1.197 + slot.put_into("error", "no abstract") 1.198 + return false 1.199 + end 1.200 + abstract = encode.html(abstract) 1.201 + draft_text = abstract .. "<!--END_OF_ABSTRACT-->" .. draft_text 1.202 + end 1.203 + 1.204 + local location = param.get("location") 1.205 + if location == "" then 1.206 + location = nil 1.207 + end 1.208 + 1.209 + if param.get("preview") or param.get("edit") then 1.210 + return false 1.211 + end 1.212 1.213 -if config.initiative_abstract then 1.214 - local abstract = param.get("abstract") 1.215 - if not abstract then 1.216 - return false 1.217 + initiative = Initiative:new() 1.218 + 1.219 + if not issue then 1.220 + issue = Issue:new() 1.221 + issue.area_id = area.id 1.222 + issue.policy_id = policy_id 1.223 + 1.224 + if policy.polling then 1.225 + issue.accepted = 'now' 1.226 + issue.state = 'discussion' 1.227 + initiative.polling = true 1.228 + 1.229 + if policy.free_timeable then 1.230 + issue.discussion_time = timing.discussion 1.231 + issue.verification_time = timing.verification 1.232 + issue.voting_time = timing.voting 1.233 + end 1.234 + 1.235 + end 1.236 + 1.237 + issue:save() 1.238 + 1.239 + if config.etherpad then 1.240 + local result = net.curl( 1.241 + config.etherpad.api_base 1.242 + .. "api/1/createGroupPad?apikey=" .. config.etherpad.api_key 1.243 + .. "&groupID=" .. config.etherpad.group_id 1.244 + .. "&padName=Issue" .. tostring(issue.id) 1.245 + .. "&text=" .. request.get_absolute_baseurl() .. "issue/show/" .. tostring(issue.id) .. ".html" 1.246 + ) 1.247 + end 1.248 + end 1.249 + 1.250 + if param.get("polling", atom.boolean) and app.session.member:has_polling_right_for_unit_id(area.unit_id) then 1.251 + initiative.polling = true 1.252 + end 1.253 + initiative.issue_id = issue.id 1.254 + initiative.name = name 1.255 + initiative:save() 1.256 + 1.257 + new_initiative = initiative 1.258 + 1.259 + local draft = Draft:new() 1.260 + draft.initiative_id = initiative.id 1.261 + draft.formatting_engine = formatting_engine 1.262 + draft.content = draft_text 1.263 + draft.location = location 1.264 + draft.author_id = app.session.member.id 1.265 + draft:save() 1.266 + 1.267 + draft_id = draft.id 1.268 + 1.269 + local initiator = Initiator:new() 1.270 + initiator.initiative_id = initiative.id 1.271 + initiator.member_id = app.session.member.id 1.272 + initiator.accepted = true 1.273 + initiator:save() 1.274 + 1.275 + if not is_polling then 1.276 + local supporter = Supporter:new() 1.277 + supporter.initiative_id = initiative.id 1.278 + supporter.member_id = app.session.member.id 1.279 + supporter.draft_id = draft.id 1.280 + supporter:save() 1.281 + end 1.282 + 1.283 end 1.284 - abstract = encode.html(abstract) 1.285 - draft_text = abstract .. "<!--END_OF_ABSTRACT-->" .. draft_text 1.286 + status = donew() 1.287 end 1.288 1.289 if config.attachments then 1.290 @@ -80,76 +326,78 @@ 1.291 fh:write(json.export(file_uploads)) 1.292 fh:write("\n") 1.293 fh:close() 1.294 -end 1.295 + 1.296 + if draft_id then 1.297 + local file_upload_session = param.get("file_upload_session") 1.298 + file_upload_session = string.gsub(file_upload_session, "[^A-Za-z0-9]", "") 1.299 1.300 -local draft_id = Draft:update_content( 1.301 - app.session.member.id, 1.302 - param.get("initiative_id", atom.integer), 1.303 - param.get("formatting_engine"), 1.304 - draft_text, 1.305 - nil, 1.306 - param.get("preview") or param.get("edit") 1.307 -) 1.308 + local draft_attachments = DraftAttachment:new_selector() 1.309 + :add_where{ "draft_attachment.draft_id = ?", draft_id } 1.310 + :exec() 1.311 + 1.312 + for i, draft_attachment in ipairs(draft_attachments) do 1.313 + if param.get("file_delete_" .. draft_attachment.file_id, atom.boolean) then 1.314 + draft_attachment:destroy() 1.315 + end 1.316 + end 1.317 1.318 -if draft_id and config.attachments then 1.319 - local file_upload_session = param.get("file_upload_session") 1.320 - file_upload_session = string.gsub(file_upload_session, "[^A-Za-z0-9]", "") 1.321 + local file_uploads = json.array() 1.322 + local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. ".json") 1.323 + local fh = io.open(filename, "r") 1.324 + if fh then 1.325 + file_uploads = json.import(fh:read("*a")) 1.326 + end 1.327 + for i, file_upload in ipairs(file_uploads) do 1.328 + local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. "-" .. file_upload.id .. ".jpg") 1.329 + local data 1.330 + local fh = io.open(filename, "r") 1.331 + if fh then 1.332 + data = fh:read("*a") 1.333 + end 1.334 + local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. "-" .. file_upload.id .. ".preview.jpg") 1.335 + local data_preview 1.336 + local fh = io.open(filename, "r") 1.337 + if fh then 1.338 + data_preview = fh:read("*a") 1.339 + end 1.340 + 1.341 + local hash = moonhash.sha3_512(data) 1.342 1.343 - local draft_attachments = DraftAttachment:new_selector() 1.344 - :add_where{ "draft_attachment.draft_id = ?", draft_id } 1.345 - :exec() 1.346 + local file = File:new_selector() 1.347 + :add_where{ "hash = ?", hash } 1.348 + :add_where{ "content_type = ?", "image/jpeg" } 1.349 + :optional_object_mode() 1.350 + :exec() 1.351 1.352 - for i, draft_attachment in ipairs(draft_attachments) do 1.353 - if param.get("file_delete_" .. draft_attachment.file_id, atom.boolean) then 1.354 - draft_attachment:destroy() 1.355 + if not file then 1.356 + file = File:new() 1.357 + file.content_type = "image/jpeg" 1.358 + file.hash = hash 1.359 + file.data = data 1.360 + file.preview_content_type = "image/jpeg" 1.361 + file.preview_data = data_preview 1.362 + file:save() 1.363 + end 1.364 + 1.365 + local draft_attachment = DraftAttachment:new() 1.366 + draft_attachment.draft_id = draft_id 1.367 + draft_attachment.file_id = file.id 1.368 + draft_attachment.title = file_upload.title 1.369 + draft_attachment.description = file_upload.description 1.370 + draft_attachment:save() 1.371 end 1.372 end 1.373 1.374 - local file_uploads = json.array() 1.375 - local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. ".json") 1.376 - local fh = io.open(filename, "r") 1.377 - if fh then 1.378 - file_uploads = json.import(fh:read("*a")) 1.379 - end 1.380 - for i, file_upload in ipairs(file_uploads) do 1.381 - local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. "-" .. file_upload.id .. ".jpg") 1.382 - local data 1.383 - local fh = io.open(filename, "r") 1.384 - if fh then 1.385 - data = fh:read("*a") 1.386 - end 1.387 - local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. "-" .. file_upload.id .. ".preview.jpg") 1.388 - local data_preview 1.389 - local fh = io.open(filename, "r") 1.390 - if fh then 1.391 - data_preview = fh:read("*a") 1.392 - end 1.393 - 1.394 - local hash = moonhash.sha3_512(data) 1.395 - 1.396 - local file = File:new_selector() 1.397 - :add_where{ "hash = ?", hash } 1.398 - :add_where{ "content_type = ?", "image/jpeg" } 1.399 - :optional_object_mode() 1.400 - :exec() 1.401 - 1.402 - if not file then 1.403 - file = File:new() 1.404 - file.content_type = "image/jpeg" 1.405 - file.hash = hash 1.406 - file.data = data 1.407 - file.preview_content_type = "image/jpeg" 1.408 - file.preview_data = data_preview 1.409 - file:save() 1.410 - end 1.411 - 1.412 - local draft_attachment = DraftAttachment:new() 1.413 - draft_attachment.draft_id = draft_id 1.414 - draft_attachment.file_id = file.id 1.415 - draft_attachment.title = file_upload.title 1.416 - draft_attachment.description = file_upload.description 1.417 - draft_attachment:save() 1.418 - end 1.419 end 1.420 1.421 -return draft_id and true or false 1.422 +print(new_initiative, status) 1.423 +if new_initiative and status ~= false then 1.424 + request.redirect{ 1.425 + module = "initiative", 1.426 + view = "show", 1.427 + id = new_initiative.id 1.428 + } 1.429 +end 1.430 + 1.431 +return status 1.432 +