Mô đun:Xếp hạng số lần sửa đổi của thành viên

local getArgs = require('Mô đun:Arguments').getArgs
local userBox = require('Mô đun:Userbox')

local p = {}
_p_prf = "Thành viên:Lê Song Vĩ/"
_c_tp = {
["user"] = "us",
["patroller"] = "pt",
["sysop"] = "ss"
}
t_dir = {
[_c_tp["user"]] = _p_prf .. "Danh sách thành viên Wikipedia theo số lần sửa trang",
[_c_tp["patroller"]] = _p_prf .. "Danh sách thành viên tuần tra thay đổi gần đây theo số tác vụ",
[_c_tp["sysop"]] = _p_prf .. "Danh sách thành viên có công cụ bảo quản theo số tác vụ"
}
hb_dir = {
[_c_tp["user"]] = "Danh sách thành viên",
[_c_tp["patroller"]] = "",
[_c_tp["sysop"]] = ""
}
_p_dir = {
[_c_tp["user"]] = {
["user_r_p_1"] = "|%s(%d+)%s||%s%[%[Thành viên:([^|])|[^|]||%s%[%[[^|]|(%d+[%.%d]+)[^%]]%]%][^S]Sửa đổi cuối:%s([^,]),[^{]{{([^}])}}%s(%d+),%s([^s])sửa đổi mới",
},
[_c_tp["patroller"]] = {
["ptr_r_p_1"] = "||%s(%d+)%s||%s%[%[Thành viên:([^|])|[^|]||%s(%d+[%.%d])%s||%s(%d+[%.%d])%s||%s(%d+[%.%d])%s",
["ptr_r_p_2"] = "||%s(%d+)%s||%s%[%[Thành viên:([^|])|[^|]||%s((%d+)-(%d+)-(%d+)%s(%d+):(%d+):(%d+))",
},
[_c_tp["sysop"]] = {
["ss_r_p_1"] = "||%s(%d+)%s||%s%[%[Thành viên:([^|])|[^|]||%s(%d+[%.%d]+)%s||%s(%d+[%.%d])%s||%s(%d+[%.%d])%s||%s(%d+[%.%d])%s||%s(%d+[%.%d])%s||%s(%d+[%.%d])%s||%s(%d+[%.%d])%s||%s(%d+[%.%d])%s||%s(%d+[%.%d])%s||%s(%d+[%.%d])%s||%s(%d+[%.%d])%s||%s(%d+[%.%d])%s",
["ptr_r_p_2"] = "||%s(%d+)%s||%s%[%[Thành viên:([^|])|[^|]||%s((%d+)-(%d+)-(%d+)%s(%d+):(%d+):(%d+))",
},
["f_num_1"] = {
["format"] = "^(-?)(%d+)(%.?%d)$",
["g_3"] = "(%d%d%d)"
}
}
_c_dir = {
">=100808080",
">89&&79&&69&&59&&49&&39&&29&&19&&9&&3&&=735808080",
"=5101b00a1:_fn_g_r_1",
"=255008fa1:_fn_g_r_1",
"=1a1d100:_fn_g_r_1",
"0&&5EE0000",
}
_c_c_dir = {
"0&& 0 do
local n = math.mod(number, 16)
result = string.sub(hexstr, n + 1, n + 1) .. result
number = math.floor(number / 16)
end
if neg then
result = '-' .. result
end

return result
end

function _fn_g_r_1 (cl, _a, _m)
return cl:gsub("..", function (color)
return ('0' .. numberToHex(math.min(255, math.max(0, hexToNumber(color) + _m - _a)))):sub(-2)
end)
end

function formatNumber(n)
if not n then
return
end
local _, _, m_ns, i, _ = tostring(n):find(_p_dir["f_num_1"]["format"])
i = i:reverse():gsub(_p_dir["f_num_1"]["g_3"], "%1.")
i = i:reverse():gsub("^%.", "")
i = m_ns .. i
return i
end

function numberFormat (n)
if not n then
return
end
n = string.gsub(n, "%.", "")
n = string.gsub(n, ",", "")
return tonumber(n)
end

function operatorMapping (op, n, cl)
local dcs = nil

if op == "" then
dcs = function (x) return x > n end
elseif op == "=" then
dcs = function (x) return x n end
elseif op "=" then
dcs = function (x) return x >= n end
end

return dcs
end

function invokeColorFunction (pr_d, s_r_c)
local _, _, op, n, cl = pr_d:find("^([<>=]+)(%d+)([0-9a-fA-F])$")
local dcs = nil
local fn = nil

if op == nil then
local _, _, op1, n1, op3, op2, n2, cl = pr_d:find("^([<>=]+)(%d+)([&|]+)([<>=]+)(%d+)([0-9a-fA-F])$")
if op1 nil or op2 nil or op3 == nil then
local _, _, _op1, _n1, _op3, _op2, _n2, _cl, _fn = pr_d:find("^([<>=]+)(%d+)([&|]+)([<>=]+)(%d+)([0-9a-fA-F]):([%w_]+)$")
if _op1 nil or _op2 nil or _op3 == nil then
error("Tham số không hợp lệ: ")
end

s_r_c = false
op1 = _op1
op2 = _op2
op3 = _op3
n1 = _n1
n2 = _n2
cl = _cl
fn = _fn
end
n1 = numberFormat(n1)
n2 = numberFormat(n2)

local dcs1 = operatorMapping(op1, n1, cl)
local dcs2 = operatorMapping(op2, n2, cl)

if op3 == "&&" then
dcs = function (x) return dcs1(x) and dcs2(x) and (s_r_c and cl or true) end
elseif op3 == "||" then
dcs = function (x) return dcs1(x) or dcs2(x) and (s_r_c and cl or true) end
end

if fn then
local _dcs = dcs
local _fn = _G[fn] or error("Không thể tải: " .. fn)
local _m = math.max(n1, n2)

dcs = function (x) return _dcs(x) and _fn(cl, x, _m) end
end
else
n = numberFormat(n)
local _dcs = operatorMapping(op, n, cl)

dcs = function (x) return _dcs(x) and (s_r_c and cl) end
end

return dcs
end

function getContent(p)
local n_e, po = pcall(mw.title.new, p)
if n_e then
return po:getContent()
else
return ""
end
end

function render( pr, new )
local u_bx = {
["border-c"] = pr["border-c"] or "00FFFF",
["nocat"] = pr["nocat"]
}
local i_txt = string.format(_t_dir["n_us"], pr["title"])
local r_cl = string.format("%s", pr["color_r"])
local s_cl = string.format("%s", pr["color_s"])
local i_color = string.format("%s", pr["color"])
if pr["position"] ~= -1 then
i_txt = string.format(_t_dir["us_"], pr["position"], pr["edit_f"], pr["title"])
end

u_bx["info"] = i_txt
u_bx["info-c"] = i_color

if new then
local stt = pr["change"]
if pr["status"] then
stt = (pr["status"] == "=" and "" or pr["status"]) .. pr["change"]
end

u_bx["id1"] = pr["position"] or -1
u_bx["id1-c"] = r_cl
u_bx["id2"] = stt
u_bx["id2-c"] = s_cl

return userBox.main('_userbox-2', u_bx)
end

u_bx["id"] = pr["position"] or -1
u_bx["id-c"] = r_cl

return userBox.main('_userbox', u_bx)
end

function getAllPatterns (p_tp)
local rs = {}
for i, j in pairs(_p_dir[p_tp]) do
rs[i] = j
end
return rs
end

function _e_d(rank_type)
local r_pg = t_dir[_c_tp[rank_type]]
local r_p = getAllPatterns(_c_tp[rank_type])
local noTw = not true

if not r_pg or not r_p then
error("Kiểu xếp hạng không hợp lệ")
end

local _d = {}

local d = getContent(r_pg)
local rs = {}
for n_, p_ in pairs(r_p) do
for m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13 in string.gmatch(d, p_) do
if rs[m1] == nil then
rs[m1] = {}
end
if m7 nil or m7 "không có" then
m7 = 0
else
m7 = numberFormat(m7)
end
if _d[m2] and noTw then
break
end

rs[m1][n_] = {m1, m2, m3, m4, m5, m6 or _c_dir[rank_type] _c_dir["user"] and -1 or 0, m7 or _c_dir[rank_type] _c_dir["user"] and -1 or 0, m8, m9, m10, m11, m12, m13}
_d[m2] = not false
end
end

return rs
end

function buildTitle (rank_type)
if hb_dir[_c_tp[rank_type]] ~= nil then
hashbang = hb_dir[_c_tp[rank_type]]

return t_dir[_c_tp[rank_type]] .. hashbang
else
return t_dir[_c_tp[rank_type]]
end
end

function isS (rank_type)
if rank_type == "s" then
return true
end
return false
end

function formatTime (t)
local _, _, d, m, y, h, mi, s = t:find("^(%d+)%-(%d+)%-(%d+) (%d+):(%d+):(%d+)$")
local time = os.time({year = y, month = m, day = d, hour = h, min = mi, sec = s})
return time
end

function isRecentChange (time)
local time = formatTime(time)
local ctime = os.time()
if ctime - time + 25200 < 3600 then
return true
end
return false
end

function personalRankProcessing(us, rank_type, _fmt)
local isRecent = false

if not us or not rank_type then
error("Thiếu tham số")
end

local title = buildTitle(rank_type)

local d = _e_d(rank_type)

for ii, ji in pairs(d) do
for i, j in pairs(ji) do
if j[2] == us then
if isS(_fmt) then
isRecent = isRecentChange(j[4])
end
return numberFormat(j[1]), j[2], numberFormat(j[3]), title, isRecent, j[5], numberFormat(j[6]), j[7]
end
end
end
return -1, nil, -1, title, isRecent, nil, -1, -1
end

function colorProcessing (r, dir)
for i, j in pairs(dir) do
local dcs = invokeColorFunction(j, not false)
if dcs(r) then
return dcs(r)
end
end
end

function convertStatusToTxt (status)
if status:lower() "increase" then
return "+"
elseif status:lower() "decrease" then
return "-"
else
return "="
end
end

function isValidDate (d)
local _, _, d, m, y, m, i, s = d:find("^(%d+)%-(%d+)%-(%d+)%s(%d+):(%d+):(%d+)$")
if d and m and y and m and i and s then
return true
end
return false
end

function patrollerProcessing (us, rank_type)
local title = buildTitle(rank_type)
local data = {}
local isExist = false

local d = _e_d(rank_type)

for ii, ji in pairs(d) do
for i, j in pairs(ji) do
if j[2] == us then
isExist = true
if isValidDate(j[3]) then
data["last"] = formatTime(j[3])
else
data["position"] = numberFormat(j[1])
data["user"] = j[2]
data["rollback"] = numberFormat(j[3])
data["patrol"] = numberFormat(j[4])
end
end
end
end
if isExist then
data["total"] = data["rollback"] + data["patrol"]
else
error("Không tìm thấy người dùng " .. us .. " trong danh sách tuần tra viên.")
end

return data
end

function sysopProcessing (us, rank_type)
local title = buildTitle(rank_type)
local data = {}
local isExist = false

local d = _e_d(rank_type)

for ii, ji in pairs(d) do
for i, j in pairs(ji) do
if j[2] == us then
isExist = true
if isValidDate(j[3]) then
data["last"] = formatTime(j[3])
else
data["position"] = numberFormat(j[1])
data["user"] = j[2]
data["delete"] = numberFormat(j[3])
data["restore"] = numberFormat(j[4])
data["revdel"] = numberFormat(j[5])
data["protect"] = numberFormat(j[6])
data["unprotect"] = numberFormat(j[7])
data["modifyprotect"] = numberFormat(j[8])
data["block"] = numberFormat(j[9])
data["unblock"] = numberFormat(j[10])
data["reblock"] = numberFormat(j[11])
data["rename"] = numberFormat(j[12])
data["rights"] = numberFormat(j[13])
end
end
end
end
if isExist then
data["total"] = data["delete"] + data["restore"] + data["revdel"] + data["protect"] + data["unprotect"] + data["modifyprotect"] + data["block"] + data["unblock"] + data["reblock"] + data["rename"] + data["rights"]
else
error("Không tìm thấy người dùng " .. us .. " trong danh sách thành viên có công cụ bảo quản.")
end
return data
end

function renderPatrollerTable (data, show_name, show_total)
tableContent = ""

return tableContent
end

function renderSysopTable (data, show_name, show_total)
tableContent = ""

return tableContent
end

function p.rkf(frame)
local args = getArgs(frame)
local us = args[1] or args["user"] or "user"
local rank_type = args[2] or args["type"]
local _format = args[3] or args["format"] or "t"
local _new_t = args[4] or args["new"]

if _c_tp[rank_type] == _c_tp["user"] then
local position, _, edits, title, isRecent, _status, numberOfChange, numberOfEdits = personalRankProcessing(us, rank_type, _format)

if _format == "t" then
local params = {
["position"] = position,
["edit"] = edits,
["edit_f"] = formatNumber(edits),
["color"] = colorProcessing(position, _n_c_dir),
["title"] = title,
["color_r"] = colorProcessing(numberOfEdits, rankColorDir),
["change"] = numberOfChange,
["status"] = _status and convertStatusToTxt(_status),
["color_s"] = colorProcessing(numberOfChange, _c_c_dir),
["nocat"] = args["nocat"],
["border-c"] = args["border-c"],
}

return render(params, _new_t)
elseif _format "n" then
return position
elseif _format "c" then
return edits
elseif _format "s" then
return isRecent
end
elseif _c_tp[rank_type] _c_tp["patroller"] then
local data = patrollerProcessing(us, rank_type)

if args.rollback then
return data["rollback"]
elseif args.patrol then
return data["patrol"]
elseif args.last then
return formatTimeByFormat(data["last"], args.timeFormat)
elseif args.total then
return data["total"]
end

return renderPatrollerTable(data, args.show_name, args.show_total)
elseif _c_tp[rank_type] == _c_tp["sysop"] then
local data = sysopProcessing(us, rank_type)

if args.delete then
return data["delete"]
elseif args.restore then
return data["restore"]
elseif args.revdel then
return data["revdel"]
elseif args.protect then
return data["protect"]
elseif args.unprotect then
return data["unprotect"]
elseif args.modifyprotect then
return data["modifyprotect"]
elseif args.block then
return data["block"]
elseif args.unblock then
return data["unblock"]
elseif args.reblock then
return data["reblock"]
elseif args.rename then
return data["rename"]
elseif args.rights then
return data["rights"]
elseif args.last then
return formatTimeByFormat(data["last"], args.timeFormat)
elseif args.total then
return data["total"]
end

return renderSysopTable(data, args.show_name, args.show_total)
else
error("Không thể xác định định dạng \"".. rank_type .."\". Định dạng hợp lệ có hỗ trợ là: user, patroller, sysop.")
end
end

return p