liquid_feedback_frontend

annotate app/main/draft/_action/add.lua @ 1751:ddbd46a34b6a

Allow API lookup of member profile fields
author bsw
date Tue Oct 12 15:37:28 2021 +0200 (2021-10-12)
parents a13a0071f873
children
rev   line source
bsw@1496 1 local initiative
bsw@1496 2 local new_initiative
bsw@1496 3 local draft_id
bsw@1496 4 local status
bsw@1496 5
bsw@1496 6 if param.get("initiative_id", atom.integer) then
bsw@1496 7
bsw@1496 8 local function donew()
bsw@1496 9 local draft_text = param.get("content")
bsw@1496 10
bsw@1496 11 if not draft_text then
bsw@1496 12 return false
bsw@1496 13 end
bsw@1496 14
bsw@1496 15 local draft_text = util.wysihtml_preproc(draft_text)
bsw@1496 16
bsw@1496 17 local valid_html, error_message = util.html_is_safe(draft_text)
bsw@1496 18 if not valid_html then
bsw@1496 19 slot.put_into("error", _("Draft contains invalid formatting or character sequence: #{error_message}", { error_message = error_message }) )
bsw@1496 20 return false
bsw@1496 21 end
bsw@1496 22
bsw@1496 23 if config.initiative_abstract then
bsw@1496 24 local abstract = param.get("abstract")
bsw@1496 25 if not abstract then
bsw@1496 26 return false
bsw@1496 27 end
bsw@1496 28 abstract = encode.html(abstract)
bsw@1496 29 draft_text = abstract .. "<!--END_OF_ABSTRACT-->" .. draft_text
bsw@1496 30 end
bsw@1496 31
bsw@1496 32 draft_id = Draft:update_content(
bsw@1496 33 app.session.member.id,
bsw@1496 34 param.get("initiative_id", atom.integer),
bsw@1496 35 param.get("formatting_engine"),
bsw@1496 36 draft_text,
bsw@1496 37 nil,
bsw@1496 38 param.get("preview") or param.get("edit")
bsw@1496 39 )
bsw@1496 40 return draft_id and true or false
bsw@1496 41 end
bsw@1496 42
bsw@1496 43 status = donew()
bsw@1496 44
bsw@1496 45 else
bsw@1496 46
bsw@1496 47 local function donew()
bsw@1496 48 local issue
bsw@1496 49 local area
bsw/jbe@1309 50
bsw@1496 51 local issue_id = param.get("issue_id", atom.integer)
bsw@1496 52 if issue_id then
bsw@1496 53 issue = Issue:new_selector():add_where{"id=?",issue_id}:for_share():single_object_mode():exec()
bsw@1496 54 if issue.closed then
bsw@1496 55 slot.put_into("error", _"This issue is already closed.")
bsw@1496 56 return false
bsw@1496 57 elseif issue.fully_frozen then
bsw@1496 58 slot.put_into("error", _"Voting for this issue has already begun.")
bsw@1496 59 return false
bsw@1496 60 elseif issue.phase_finished then
bsw@1496 61 slot.put_into("error", _"Current phase is already closed.")
bsw@1496 62 return false
bsw@1496 63 end
bsw@1496 64 area = issue.area
bsw@1496 65 else
bsw@1496 66 local area_id = param.get("area_id", atom.integer)
bsw@1496 67 area = Area:new_selector():add_where{"id=?",area_id}:single_object_mode():exec()
bsw@1496 68 if not area.active then
bsw@1496 69 slot.put_into("error", "Invalid area.")
bsw@1496 70 return false
bsw@1496 71 end
bsw@1496 72 end
bsw@1496 73
bsw@1496 74 if not app.session.member:has_voting_right_for_unit_id(area.unit_id) then
bsw@1496 75 return execute.view { module = "index", view = "403" }
bsw@1496 76 end
bsw@1496 77
bsw@1496 78 local policy_id = param.get("policy_id", atom.integer)
bsw@1496 79 local policy
bsw@1496 80 if policy_id then
bsw@1496 81 policy = Policy:by_id(policy_id)
bsw@1496 82 end
bsw/jbe@1309 83
bsw@1496 84 if not issue then
bsw@1496 85 if policy_id == -1 then
bsw@1496 86 slot.put_into("error", _"Please choose a policy")
bsw@1496 87 return false
bsw@1496 88 end
bsw@1496 89 if not policy.active then
bsw@1496 90 slot.put_into("error", "Invalid policy.")
bsw@1496 91 return false
bsw@1496 92 end
bsw@1496 93 if policy.polling and not app.session.member:has_polling_right_for_unit_id(area.unit_id) then
bsw@1496 94 return execute.view { module = "index", view = "403" }
bsw@1496 95 end
bsw@1496 96 if not area:get_reference_selector("allowed_policies")
bsw@1496 97 :add_where{ "policy.id = ?", policy_id }
bsw@1496 98 :optional_object_mode()
bsw@1496 99 :exec()
bsw@1496 100 then
bsw@1496 101 slot.put_into("error", "policy not allowed")
bsw@1496 102 return false
bsw@1496 103 end
bsw@1496 104 end
bsw@1496 105
bsw@1496 106 local is_polling = (issue and param.get("polling", atom.boolean)) or (policy and policy.polling) or false
bsw@1496 107
bsw@1496 108 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")
bsw@1496 109 if not tmp or tmp.initiatives_left < 1 then
bsw@1496 110 slot.put_into("error", _"Sorry, your contingent for creating initiatives has been used up. Please try again later.")
bsw@1496 111 return false
bsw@1496 112 end
bsw@1496 113 if tmp and tmp.text_entries_left < 1 then
bsw@1496 114 slot.put_into("error", _"Sorry, you have reached your personal flood limit. Please be slower...")
bsw@1496 115 return false
bsw@1496 116 end
bsw@1496 117
bsw@1496 118 local name = param.get("name")
bsw@1496 119
bsw@1496 120 local name = util.trim(name)
bsw@1496 121
bsw@1496 122 if #name < 3 then
bsw@1496 123 slot.put_into("error", _"Please enter a meaningful title for your initiative!")
bsw@1496 124 return false
bsw@1496 125 end
bsw@1496 126
bsw@1496 127 if #name > 140 then
bsw@1496 128 slot.put_into("error", _"This title is too long!")
bsw@1496 129 return false
bsw@1496 130 end
bsw/jbe@1309 131
bsw@1496 132 local timing
bsw@1496 133 if not issue and policy.free_timeable then
bsw@1496 134 local free_timing_string = util.trim(param.get("free_timing"))
bsw@1496 135 if not free_timing_string or #free_timing_string < 1 then
bsw@1496 136 slot.put_into("error", _"Choose timing")
bsw@1496 137 return false
bsw@1496 138 end
bsw@1496 139 local available_timings
bsw@1496 140 if config.free_timing and config.free_timing.available_func then
bsw@1496 141 available_timings = config.free_timing.available_func(policy)
bsw@1496 142 if available_timings == false then
bsw@1496 143 slot.put_into("error", "error in free timing config")
bsw@1496 144 return false
bsw@1496 145 end
bsw@1496 146 end
bsw@1496 147 if available_timings then
bsw@1496 148 local timing_available = false
bsw@1496 149 for i, available_timing in ipairs(available_timings) do
bsw@1496 150 if available_timing.id == free_timing_string then
bsw@1496 151 timing_available = true
bsw@1496 152 end
bsw@1496 153 end
bsw@1496 154 if not timing_available then
bsw@1496 155 slot.put_into("error", _"Invalid timing")
bsw@1496 156 return false
bsw@1496 157 end
bsw@1496 158 end
bsw@1496 159 timing = config.free_timing.calculate_func(policy, free_timing_string)
bsw@1496 160 if not timing then
bsw@1496 161 slot.put_into("error", "error in free timing config")
bsw@1496 162 return false
bsw@1496 163 end
bsw@1496 164 end
bsw@1496 165
bsw@1496 166 local draft_text = param.get("content")
bsw@1496 167
bsw@1496 168 if not draft_text then
bsw@1496 169 slot.put_into("error", "no draft text")
bsw@1496 170 return false
bsw@1496 171 end
bsw@1496 172
bsw@1496 173 local draft_text = util.wysihtml_preproc(draft_text)
bsw@1496 174
bsw@1496 175 local valid_html, error_message = util.html_is_safe(draft_text)
bsw@1496 176 if not valid_html then
bsw@1496 177 slot.put_into("error", _("Draft contains invalid formatting or character sequence: #{error_message}", { error_message = error_message }) )
bsw@1496 178 return false
bsw@1496 179 end
bsw@1496 180
bsw@1496 181 if config.initiative_abstract then
bsw@1496 182 local abstract = param.get("abstract")
bsw@1496 183 if not abstract then
bsw@1496 184 slot.put_into("error", "no abstract")
bsw@1496 185 return false
bsw@1496 186 end
bsw@1496 187 abstract = encode.html(abstract)
bsw@1496 188 draft_text = abstract .. "<!--END_OF_ABSTRACT-->" .. draft_text
bsw@1496 189 end
bsw@1496 190
bsw@1496 191 local location = param.get("location")
bsw@1496 192 if location == "" then
bsw@1496 193 location = nil
bsw@1496 194 end
bsw@1550 195
bsw@1550 196 local external_reference
bsw@1550 197 if config.firstlife then
bsw@1550 198 external_reference = param.get("external_reference")
bsw@1550 199 end
bsw@1496 200
bsw@1496 201 if param.get("preview") or param.get("edit") then
bsw@1496 202 return false
bsw@1496 203 end
bsw/jbe@1309 204
bsw@1496 205 initiative = Initiative:new()
bsw@1496 206
bsw@1496 207 if not issue then
bsw@1496 208 issue = Issue:new()
bsw@1496 209 issue.area_id = area.id
bsw@1496 210 issue.policy_id = policy_id
bsw@1496 211
bsw@1496 212 if policy.polling then
bsw@1496 213 issue.accepted = 'now'
bsw@1496 214 issue.state = 'discussion'
bsw@1496 215 initiative.polling = true
bsw@1496 216
bsw@1496 217 if policy.free_timeable then
bsw@1496 218 issue.discussion_time = timing.discussion
bsw@1496 219 issue.verification_time = timing.verification
bsw@1496 220 issue.voting_time = timing.voting
bsw@1496 221 end
bsw@1496 222
bsw@1496 223 end
bsw@1496 224
bsw@1496 225 issue:save()
bsw@1496 226
bsw@1496 227 if config.etherpad then
bsw@1496 228 local result = net.curl(
bsw@1496 229 config.etherpad.api_base
bsw@1496 230 .. "api/1/createGroupPad?apikey=" .. config.etherpad.api_key
bsw@1496 231 .. "&groupID=" .. config.etherpad.group_id
bsw@1496 232 .. "&padName=Issue" .. tostring(issue.id)
bsw@1496 233 .. "&text=" .. request.get_absolute_baseurl() .. "issue/show/" .. tostring(issue.id) .. ".html"
bsw@1496 234 )
bsw@1496 235 end
bsw@1496 236 end
bsw@1496 237
bsw@1496 238 if param.get("polling", atom.boolean) and app.session.member:has_polling_right_for_unit_id(area.unit_id) then
bsw@1496 239 initiative.polling = true
bsw@1496 240 end
bsw@1496 241 initiative.issue_id = issue.id
bsw@1496 242 initiative.name = name
bsw@1550 243 initiative.external_reference = external_reference
bsw@1496 244 initiative:save()
bsw@1496 245
bsw@1496 246 new_initiative = initiative
bsw@1496 247
bsw@1496 248 local draft = Draft:new()
bsw@1496 249 draft.initiative_id = initiative.id
bsw@1496 250 draft.formatting_engine = formatting_engine
bsw@1496 251 draft.content = draft_text
bsw@1496 252 draft.location = location
bsw@1496 253 draft.author_id = app.session.member.id
bsw@1496 254 draft:save()
bsw@1496 255
bsw@1496 256 draft_id = draft.id
bsw@1496 257
bsw@1496 258 local initiator = Initiator:new()
bsw@1496 259 initiator.initiative_id = initiative.id
bsw@1496 260 initiator.member_id = app.session.member.id
bsw@1496 261 initiator.accepted = true
bsw@1496 262 initiator:save()
bsw@1496 263
bsw@1496 264 if not is_polling then
bsw@1496 265 local supporter = Supporter:new()
bsw@1496 266 supporter.initiative_id = initiative.id
bsw@1496 267 supporter.member_id = app.session.member.id
bsw@1496 268 supporter.draft_id = draft.id
bsw@1496 269 supporter:save()
bsw@1496 270 end
bsw@1496 271
bsw/jbe@1309 272 end
bsw@1496 273 status = donew()
bsw/jbe@1309 274 end
bsw/jbe@1309 275
bsw@1495 276 if config.attachments then
bsw@1495 277 local file_upload_session = param.get("file_upload_session")
bsw@1495 278 file_upload_session = string.gsub(file_upload_session, "[^A-Za-z0-9]", "")
bsw@1495 279 local file_uploads = json.array()
bsw@1495 280 local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. ".json")
bsw@1495 281 local fh = io.open(filename, "r")
bsw@1495 282 if fh then
bsw@1495 283 file_uploads = json.import(fh:read("*a"))
bsw@1495 284 end
bsw@1495 285 for i, file_upload in ipairs(file_uploads) do
bsw@1495 286 if param.get("file_upload_delete_" .. file_upload.id, atom.boolean) then
bsw@1495 287 for j = i, #file_uploads - 1 do
bsw@1495 288 file_uploads[j] = file_uploads[j+1]
bsw@1495 289 end
bsw@1495 290 file_uploads[#file_uploads] = nil
bsw@1495 291 end
bsw@1495 292 end
bsw@1495 293 local convert_func = config.attachments.convert_func
bsw@1495 294 local last_id = param.get("file_upload_last_id", atom.number)
bsw@1495 295 if last_id and last_id > 0 then
bsw@1495 296 if last_id > 1024 then
bsw@1495 297 last_id = 1024
bsw@1495 298 end
bsw@1495 299 for i = 1, last_id do
bsw@1495 300 local file = param.get("file_" .. i)
bsw@1495 301 if file and #file > 0 then
bsw@1495 302 local id = multirand.string(
bsw@1495 303 32,
bsw@1495 304 '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
bsw@1495 305 )
bsw@1495 306 local data, err, status = convert_func(file)
bsw@1495 307 if status ~= 0 or data == nil then
bsw@1495 308 slot.put_into("error", _"Error while converting image. Please note, that only JPG files are supported!")
bsw@1495 309 return false
bsw@1495 310 end
bsw@1495 311 local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. "-" .. id .. ".jpg")
bsw@1495 312 local fh = assert(io.open(filename, "w"))
bsw@1495 313 fh:write(file)
bsw@1495 314 fh:write("\n")
bsw@1495 315 fh:close()
bsw@1495 316 local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. "-" .. id .. ".preview.jpg")
bsw@1495 317 local fh = assert(io.open(filename, "w"))
bsw@1495 318 fh:write(data)
bsw@1495 319 fh:write("\n")
bsw@1495 320 fh:close()
bsw@1495 321 table.insert(file_uploads, json.object{
bsw@1495 322 id = id,
bsw@1495 323 filename = filename,
bsw@1495 324 title = param.get("title_" .. i),
bsw@1495 325 description = param.get("description_" .. i)
bsw@1495 326 })
bsw@1495 327 end
bsw@1495 328 end
bsw@1495 329 end
bsw@1495 330 local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. ".json")
bsw@1495 331 local fh = assert(io.open(filename, "w"))
bsw@1495 332 fh:write(json.export(file_uploads))
bsw@1495 333 fh:write("\n")
bsw@1495 334 fh:close()
bsw@1496 335
bsw@1496 336 if draft_id then
bsw@1496 337 local file_upload_session = param.get("file_upload_session")
bsw@1496 338 file_upload_session = string.gsub(file_upload_session, "[^A-Za-z0-9]", "")
bsw@1495 339
bsw@1496 340 local draft_attachments = DraftAttachment:new_selector()
bsw@1496 341 :add_where{ "draft_attachment.draft_id = ?", draft_id }
bsw@1496 342 :exec()
bsw@1496 343
bsw@1496 344 for i, draft_attachment in ipairs(draft_attachments) do
bsw@1496 345 if param.get("file_delete_" .. draft_attachment.file_id, atom.boolean) then
bsw@1496 346 draft_attachment:destroy()
bsw@1496 347 end
bsw@1496 348 end
bsw@1495 349
bsw@1496 350 local file_uploads = json.array()
bsw@1496 351 local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. ".json")
bsw@1496 352 local fh = io.open(filename, "r")
bsw@1496 353 if fh then
bsw@1496 354 file_uploads = json.import(fh:read("*a"))
bsw@1496 355 end
bsw@1496 356 for i, file_upload in ipairs(file_uploads) do
bsw@1496 357 local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. "-" .. file_upload.id .. ".jpg")
bsw@1496 358 local data
bsw@1496 359 local fh = io.open(filename, "r")
bsw@1496 360 if fh then
bsw@1496 361 data = fh:read("*a")
bsw@1496 362 end
bsw@1496 363 local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. "-" .. file_upload.id .. ".preview.jpg")
bsw@1496 364 local data_preview
bsw@1496 365 local fh = io.open(filename, "r")
bsw@1496 366 if fh then
bsw@1496 367 data_preview = fh:read("*a")
bsw@1496 368 end
bsw@1496 369
bsw@1496 370 local hash = moonhash.sha3_512(data)
bsw@1495 371
bsw@1496 372 local file = File:new_selector()
bsw@1496 373 :add_where{ "hash = ?", hash }
bsw@1496 374 :add_where{ "content_type = ?", "image/jpeg" }
bsw@1496 375 :optional_object_mode()
bsw@1496 376 :exec()
bsw@1495 377
bsw@1496 378 if not file then
bsw@1496 379 file = File:new()
bsw@1496 380 file.content_type = "image/jpeg"
bsw@1496 381 file.hash = hash
bsw@1496 382 file.data = data
bsw@1496 383 file.preview_content_type = "image/jpeg"
bsw@1496 384 file.preview_data = data_preview
bsw@1496 385 file:save()
bsw@1496 386 end
bsw@1496 387
bsw@1496 388 local draft_attachment = DraftAttachment:new()
bsw@1496 389 draft_attachment.draft_id = draft_id
bsw@1496 390 draft_attachment.file_id = file.id
bsw@1496 391 draft_attachment.title = file_upload.title
bsw@1496 392 draft_attachment.description = file_upload.description
bsw@1496 393 draft_attachment:save()
bsw@1495 394 end
bsw@1495 395 end
bsw@1495 396
bsw@1495 397 end
bsw@1495 398
bsw@1496 399 if new_initiative and status ~= false then
bsw@1535 400 local callback = param.get("callback")
bsw@1535 401 if config.allow_new_draft_callback and callback then
bsw@1535 402 request.redirect{ external = callback }
bsw@1535 403 else
bsw@1535 404 request.redirect{
bsw@1535 405 module = "initiative",
bsw@1535 406 view = "show",
bsw@1535 407 id = new_initiative.id
bsw@1535 408 }
bsw@1535 409 end
bsw@1496 410 end
bsw@1496 411
bsw@1496 412 return status
bsw@1496 413

Impressum / About Us