File

util/xtemplate.lua @ 13633:6b84d11aa09b

mod_storage_sql: Detect SQLite3 without UPSERT (or SQLCipher 3.x) SQLCipher v3.4.1 (the version in Debian 12) is based on SQLite3 v3.15.2, while UPSERT support was introduced in SQLite3 v3.24.0 This check was not needed before because we v3.24.0 has not been in a version of Debian we support for a long, long time. Note however that SQLCipher databases are not compatible across major versions, upgrading from v3.x to v4.x requires executing a migration. Attempts at making `prosodyctl mod_storage_sql upgrade` perform such a migration has not been successful. Executing the following in the `sqlcipher` tool should do the migration: PRAGMA key = '<key material>'; PRAGMA cipher_migrate;
author Kim Alvefur <zash@zash.se>
date Thu, 23 Jan 2025 19:33:05 +0100
parent 13525:0f7e7311eebf
line wrap: on
line source

local s_gsub = string.gsub;
local s_match = string.match;
local s_sub = string.sub;
local t_concat = table.concat;

local st = require("prosody.util.stanza");

local function render(template, root, escape, filters)
	escape = escape or st.xml_escape;

	return (s_gsub(template, "(%s*)(%b{})(%s*)", function(pre_blank, block, post_blank)
		local inner = s_sub(block, 2, -2);
		if inner:sub(1, 1) == "-" then
			pre_blank = "";
			inner = inner:sub(2);
		end
		if inner:sub(-1, -1) == "-" then
			post_blank = "";
			inner = inner:sub(1, -2);
		end
		local path, pipe, pos = s_match(inner, "^([^|]+)(|?)()");
		if not (type(path) == "string") then return end
		local value
		if path == "." then
			value = root;
		elseif path == "#" then
			value = root:get_text();
		else
			value = root:find(path);
		end
		local is_escaped = false;

		while pipe == "|" do
			local func, args, tmpl, p = s_match(inner, "^(%w+)(%b())(%b{})()", pos);
			if not func then func, args, p = s_match(inner, "^(%w+)(%b())()", pos); end
			if not func then func, tmpl, p = s_match(inner, "^(%w+)(%b{})()", pos); end
			if not func then func, p = s_match(inner, "^(%w+)()", pos); end
			if not func then break end
			if tmpl then tmpl = s_sub(tmpl, 2, -2); end
			if args then args = s_sub(args, 2, -2); end

			if func == "each" and tmpl then
				if not st.is_stanza(value) then return pre_blank .. post_blank end
				if not args then value, args = root, path; end
				local ns, name = s_match(args, "^(%b{})(.*)$");
				if ns then
					ns = s_sub(ns, 2, -2);
				else
					name, ns = args, nil;
				end
				if ns == "" then ns = nil; end
				if name == "" then name = nil; end
				local out, i = {}, 1;
				for c in (value):childtags(name, ns) do out[i], i = render(tmpl, c, escape, filters), i + 1; end
				value = t_concat(out);
				is_escaped = true;
			elseif func == "and" and tmpl then
				local condition = value;
				if args then condition = root:find(args); end
				if condition then
					value = render(tmpl, root, escape, filters);
					is_escaped = true;
				end
			elseif func == "or" and tmpl then
				local condition = value;
				if args then condition = root:find(args); end
				if not condition then
					value = render(tmpl, root, escape, filters);
					is_escaped = true;
				end
			elseif filters and filters[func] then
				local f = filters[func];
				value, is_escaped = f(value, args, tmpl);
			else
				error("No such filter function: " .. func);
			end
			pipe, pos = s_match(inner, "^(|?)()", p);
		end

		if type(value) == "string" then
			if not is_escaped then value = escape(value); end
			return pre_blank .. value .. post_blank
		elseif st.is_stanza(value) then
			value = value:get_text();
			if value then return pre_blank .. escape(value) .. post_blank end
		end
		return pre_blank .. post_blank
	end))
end

return { render = render }