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 (23 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
