liquid_feedback_frontend

view app/main/draft/_action/add.lua @ 1859:02c34183b6df

Fixed wrong filename in INSTALL file
author bsw
date Tue Nov 28 18:54:51 2023 +0100 (5 months ago)
parents a13a0071f873
children
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 local external_reference
197 if config.firstlife then
198 external_reference = param.get("external_reference")
199 end
201 if param.get("preview") or param.get("edit") then
202 return false
203 end
205 initiative = Initiative:new()
207 if not issue then
208 issue = Issue:new()
209 issue.area_id = area.id
210 issue.policy_id = policy_id
212 if policy.polling then
213 issue.accepted = 'now'
214 issue.state = 'discussion'
215 initiative.polling = true
217 if policy.free_timeable then
218 issue.discussion_time = timing.discussion
219 issue.verification_time = timing.verification
220 issue.voting_time = timing.voting
221 end
223 end
225 issue:save()
227 if config.etherpad then
228 local result = net.curl(
229 config.etherpad.api_base
230 .. "api/1/createGroupPad?apikey=" .. config.etherpad.api_key
231 .. "&groupID=" .. config.etherpad.group_id
232 .. "&padName=Issue" .. tostring(issue.id)
233 .. "&text=" .. request.get_absolute_baseurl() .. "issue/show/" .. tostring(issue.id) .. ".html"
234 )
235 end
236 end
238 if param.get("polling", atom.boolean) and app.session.member:has_polling_right_for_unit_id(area.unit_id) then
239 initiative.polling = true
240 end
241 initiative.issue_id = issue.id
242 initiative.name = name
243 initiative.external_reference = external_reference
244 initiative:save()
246 new_initiative = initiative
248 local draft = Draft:new()
249 draft.initiative_id = initiative.id
250 draft.formatting_engine = formatting_engine
251 draft.content = draft_text
252 draft.location = location
253 draft.author_id = app.session.member.id
254 draft:save()
256 draft_id = draft.id
258 local initiator = Initiator:new()
259 initiator.initiative_id = initiative.id
260 initiator.member_id = app.session.member.id
261 initiator.accepted = true
262 initiator:save()
264 if not is_polling then
265 local supporter = Supporter:new()
266 supporter.initiative_id = initiative.id
267 supporter.member_id = app.session.member.id
268 supporter.draft_id = draft.id
269 supporter:save()
270 end
272 end
273 status = donew()
274 end
276 if config.attachments then
277 local file_upload_session = param.get("file_upload_session")
278 file_upload_session = string.gsub(file_upload_session, "[^A-Za-z0-9]", "")
279 local file_uploads = json.array()
280 local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. ".json")
281 local fh = io.open(filename, "r")
282 if fh then
283 file_uploads = json.import(fh:read("*a"))
284 end
285 for i, file_upload in ipairs(file_uploads) do
286 if param.get("file_upload_delete_" .. file_upload.id, atom.boolean) then
287 for j = i, #file_uploads - 1 do
288 file_uploads[j] = file_uploads[j+1]
289 end
290 file_uploads[#file_uploads] = nil
291 end
292 end
293 local convert_func = config.attachments.convert_func
294 local last_id = param.get("file_upload_last_id", atom.number)
295 if last_id and last_id > 0 then
296 if last_id > 1024 then
297 last_id = 1024
298 end
299 for i = 1, last_id do
300 local file = param.get("file_" .. i)
301 if file and #file > 0 then
302 local id = multirand.string(
303 32,
304 '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
305 )
306 local data, err, status = convert_func(file)
307 if status ~= 0 or data == nil then
308 slot.put_into("error", _"Error while converting image. Please note, that only JPG files are supported!")
309 return false
310 end
311 local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. "-" .. id .. ".jpg")
312 local fh = assert(io.open(filename, "w"))
313 fh:write(file)
314 fh:write("\n")
315 fh:close()
316 local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. "-" .. id .. ".preview.jpg")
317 local fh = assert(io.open(filename, "w"))
318 fh:write(data)
319 fh:write("\n")
320 fh:close()
321 table.insert(file_uploads, json.object{
322 id = id,
323 filename = filename,
324 title = param.get("title_" .. i),
325 description = param.get("description_" .. i)
326 })
327 end
328 end
329 end
330 local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. ".json")
331 local fh = assert(io.open(filename, "w"))
332 fh:write(json.export(file_uploads))
333 fh:write("\n")
334 fh:close()
336 if draft_id then
337 local file_upload_session = param.get("file_upload_session")
338 file_upload_session = string.gsub(file_upload_session, "[^A-Za-z0-9]", "")
340 local draft_attachments = DraftAttachment:new_selector()
341 :add_where{ "draft_attachment.draft_id = ?", draft_id }
342 :exec()
344 for i, draft_attachment in ipairs(draft_attachments) do
345 if param.get("file_delete_" .. draft_attachment.file_id, atom.boolean) then
346 draft_attachment:destroy()
347 end
348 end
350 local file_uploads = json.array()
351 local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. ".json")
352 local fh = io.open(filename, "r")
353 if fh then
354 file_uploads = json.import(fh:read("*a"))
355 end
356 for i, file_upload in ipairs(file_uploads) do
357 local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. "-" .. file_upload.id .. ".jpg")
358 local data
359 local fh = io.open(filename, "r")
360 if fh then
361 data = fh:read("*a")
362 end
363 local filename = encode.file_path(WEBMCP_BASE_PATH, 'tmp', "file_upload-" .. file_upload_session .. "-" .. file_upload.id .. ".preview.jpg")
364 local data_preview
365 local fh = io.open(filename, "r")
366 if fh then
367 data_preview = fh:read("*a")
368 end
370 local hash = moonhash.sha3_512(data)
372 local file = File:new_selector()
373 :add_where{ "hash = ?", hash }
374 :add_where{ "content_type = ?", "image/jpeg" }
375 :optional_object_mode()
376 :exec()
378 if not file then
379 file = File:new()
380 file.content_type = "image/jpeg"
381 file.hash = hash
382 file.data = data
383 file.preview_content_type = "image/jpeg"
384 file.preview_data = data_preview
385 file:save()
386 end
388 local draft_attachment = DraftAttachment:new()
389 draft_attachment.draft_id = draft_id
390 draft_attachment.file_id = file.id
391 draft_attachment.title = file_upload.title
392 draft_attachment.description = file_upload.description
393 draft_attachment:save()
394 end
395 end
397 end
399 if new_initiative and status ~= false then
400 local callback = param.get("callback")
401 if config.allow_new_draft_callback and callback then
402 request.redirect{ external = callback }
403 else
404 request.redirect{
405 module = "initiative",
406 view = "show",
407 id = new_initiative.id
408 }
409 end
410 end
412 return status

Impressum / About Us