liquid_feedback_frontend

view app/main/draft/_action/add.lua @ 1535:770ab0a7f79b

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

Impressum / About Us