generated from your-land/yl_template
Formatting
This commit is contained in:
parent
281fd59455
commit
1edbfca06b
12
api.lua
12
api.lua
@ -57,7 +57,8 @@ function yl_announcements.set(message, frequency, runtime, owner)
|
||||
|
||||
yl_announcements.data[index] = content
|
||||
|
||||
local success = yl_announcements.save_json(tostring(index) .. ".json", content)
|
||||
local success = yl_announcements.save_json(tostring(index) .. ".json",
|
||||
content)
|
||||
|
||||
if (success == true) then return true, index end
|
||||
return false, "Could not store announcement"
|
||||
@ -75,8 +76,10 @@ function yl_announcements.formspec(announcement_id)
|
||||
end
|
||||
|
||||
local success, announcement = yl_announcements.get(announcement_id)
|
||||
core.log("action","announcement = " .. dump(announcement))
|
||||
if ((success == false) or (announcement == nil)) then return false, "No announcement" end
|
||||
core.log("action", "announcement = " .. dump(announcement))
|
||||
if ((success == false) or (announcement == nil)) then
|
||||
return false, "No announcement"
|
||||
end
|
||||
|
||||
local m = announcement.message or "message"
|
||||
local f = announcement.frequency or "frequency"
|
||||
@ -111,7 +114,8 @@ function yl_announcements.delete(announcement_id)
|
||||
|
||||
if (announcement ~= nil) then
|
||||
data[announcement_id] = nil
|
||||
local success_f, err = yl_announcements.remove_file(announcement_id .. ".json")
|
||||
local success_f, err = yl_announcements.remove_file(announcement_id ..
|
||||
".json")
|
||||
if (success_f == nil) then return false, err end
|
||||
success = true
|
||||
end
|
||||
|
||||
@ -2,18 +2,20 @@ local chatcommand_cmd = "announcement_add"
|
||||
local chatcommand_definition = {
|
||||
params = "<message>$<frequency in minutes>$<runtime in minutes>",
|
||||
description = "Sends the message each frequency minutes for a maximum number of runtime minutes.",
|
||||
privs = {
|
||||
[yl_announcements.settings.admin_privs] = true
|
||||
},
|
||||
privs = {[yl_announcements.settings.admin_privs] = true},
|
||||
func = function(name, param)
|
||||
local success, message = yl_announcements.chatcommand_announcement_add(name, param)
|
||||
local success, message = yl_announcements.chatcommand_announcement_add(
|
||||
name, param)
|
||||
|
||||
if success then
|
||||
minetest.log("action", "[yl_announcements] player " .. name .. " added new announcement: " .. param)
|
||||
minetest.log("action", "[yl_announcements] player " .. name ..
|
||||
" added new announcement: " .. param)
|
||||
return true, message
|
||||
else
|
||||
minetest.log("warning", "[yl_announcements] player " .. name .. " added new announcement: " .. param ..
|
||||
" unsuccessfully, message: " .. message)
|
||||
minetest.log("warning",
|
||||
"[yl_announcements] player " .. name ..
|
||||
" added new announcement: " .. param ..
|
||||
" unsuccessfully, message: " .. message)
|
||||
return false, message
|
||||
end
|
||||
end
|
||||
|
||||
@ -2,18 +2,20 @@ local chatcommand_cmd = "announcement_copy"
|
||||
local chatcommand_definition = {
|
||||
params = "<announcement ID>", -- Short parameter description
|
||||
description = "Open the announcement with ID in a formspec, so it can be copied.", -- Full description
|
||||
privs = {
|
||||
[yl_announcements.settings.user_privs] = true
|
||||
},
|
||||
privs = {[yl_announcements.settings.user_privs] = true},
|
||||
func = function(name, param)
|
||||
local success, message = yl_announcements.chatcommand_announcement_copy(name, param)
|
||||
local success, message = yl_announcements.chatcommand_announcement_copy(
|
||||
name, param)
|
||||
|
||||
if success then
|
||||
minetest.log("action", "[yl_announcements] player " .. name .. " copied announcement: " .. param)
|
||||
minetest.log("action", "[yl_announcements] player " .. name ..
|
||||
" copied announcement: " .. param)
|
||||
return true, message
|
||||
else
|
||||
minetest.log("warning", "[yl_announcements] player " .. name .. " copied announcement: " .. param ..
|
||||
" unsuccessfully, message: " .. message)
|
||||
minetest.log("warning",
|
||||
"[yl_announcements] player " .. name ..
|
||||
" copied announcement: " .. param ..
|
||||
" unsuccessfully, message: " .. message)
|
||||
return false, message
|
||||
end
|
||||
end
|
||||
|
||||
@ -2,19 +2,20 @@ local chatcommand_cmd = "announcement_delete"
|
||||
local chatcommand_definition = {
|
||||
params = "<announcement ID>", -- Short parameter description
|
||||
description = "Delete the announcement ID.", -- Full description
|
||||
privs = {
|
||||
[yl_announcements.settings.admin_privs] = true
|
||||
},
|
||||
privs = {[yl_announcements.settings.admin_privs] = true},
|
||||
func = function(name, param)
|
||||
local success, message = yl_announcements.chatcommand_announcement_delete(name, param)
|
||||
local success, message =
|
||||
yl_announcements.chatcommand_announcement_delete(name, param)
|
||||
|
||||
if success then
|
||||
minetest.log("action", "[yl_announcements] player " .. name .. " deleted new announcement: " .. param)
|
||||
minetest.log("action", "[yl_announcements] player " .. name ..
|
||||
" deleted new announcement: " .. param)
|
||||
return true, message
|
||||
else
|
||||
minetest.log("warning",
|
||||
"[yl_announcements] player " .. name .. " deleted new announcement: " .. param ..
|
||||
" unsuccessfully, message: " .. message)
|
||||
"[yl_announcements] player " .. name ..
|
||||
" deleted new announcement: " .. param ..
|
||||
" unsuccessfully, message: " .. message)
|
||||
return false, message
|
||||
end
|
||||
end
|
||||
|
||||
@ -2,18 +2,20 @@ local chatcommand_cmd = "announcement_list"
|
||||
local chatcommand_definition = {
|
||||
params = "<announcement ID>", -- Short parameter description
|
||||
description = "List announcement with ID to you.", -- Full description
|
||||
privs = {
|
||||
[yl_announcements.settings.user_privs] = true
|
||||
},
|
||||
privs = {[yl_announcements.settings.user_privs] = true},
|
||||
func = function(name, param)
|
||||
local success, message = yl_announcements.chatcommand_announcement_list(name, param)
|
||||
local success, message = yl_announcements.chatcommand_announcement_list(
|
||||
name, param)
|
||||
|
||||
if success then
|
||||
minetest.log("action", "[yl_announcements] player " .. name .. " lists announcement: " .. param)
|
||||
minetest.log("action", "[yl_announcements] player " .. name ..
|
||||
" lists announcement: " .. param)
|
||||
return true, message
|
||||
else
|
||||
minetest.log("warning", "[yl_announcements] player " .. name .. " lists announcement: " .. param ..
|
||||
" unsuccessfully, message: " .. message)
|
||||
minetest.log("warning",
|
||||
"[yl_announcements] player " .. name ..
|
||||
" lists announcement: " .. param ..
|
||||
" unsuccessfully, message: " .. message)
|
||||
return false, message
|
||||
end
|
||||
end
|
||||
|
||||
@ -2,19 +2,20 @@ local chatcommand_cmd = "announcement_list_all"
|
||||
local chatcommand_definition = {
|
||||
params = "", -- Short parameter description
|
||||
description = "Lists all announcements to you.", -- Full description
|
||||
privs = {
|
||||
[yl_announcements.settings.user_privs] = true
|
||||
},
|
||||
privs = {[yl_announcements.settings.user_privs] = true},
|
||||
func = function(name, param)
|
||||
local success, message = yl_announcements.chatcommand_announcement_list_all(name, param)
|
||||
local success, message =
|
||||
yl_announcements.chatcommand_announcement_list_all(name, param)
|
||||
|
||||
if success then
|
||||
minetest.log("action", "[yl_announcements] player " .. name .. " lists all announcements: " .. param)
|
||||
minetest.log("action", "[yl_announcements] player " .. name ..
|
||||
" lists all announcements: " .. param)
|
||||
return true, message
|
||||
else
|
||||
minetest.log("warning",
|
||||
"[yl_announcements] player " .. name .. " lists all announcements: " .. param ..
|
||||
" unsuccessfully, message: " .. dump(message))
|
||||
"[yl_announcements] player " .. name ..
|
||||
" lists all announcements: " .. param ..
|
||||
" unsuccessfully, message: " .. dump(message))
|
||||
return false, dump(message)
|
||||
end
|
||||
end
|
||||
|
||||
@ -2,18 +2,20 @@ local chatcommand_cmd = "announcement_say"
|
||||
local chatcommand_definition = {
|
||||
params = "<announcement ID>", -- Short parameter description
|
||||
description = "Say the announcement with ID in main chat.", -- Full description
|
||||
privs = {
|
||||
[yl_announcements.settings.admin_privs] = true
|
||||
},
|
||||
privs = {[yl_announcements.settings.admin_privs] = true},
|
||||
func = function(name, param)
|
||||
local success, message = yl_announcements.chatcommand_announcement_say(name, param)
|
||||
local success, message = yl_announcements.chatcommand_announcement_say(
|
||||
name, param)
|
||||
|
||||
if success then
|
||||
minetest.log("action", "[yl_announcements] player " .. name .. " sent announcement: " .. param)
|
||||
minetest.log("action", "[yl_announcements] player " .. name ..
|
||||
" sent announcement: " .. param)
|
||||
return true, message
|
||||
else
|
||||
minetest.log("warning", "[yl_announcements] player " .. name .. " sent announcement: " .. param ..
|
||||
" unsuccessfully, message: " .. message)
|
||||
minetest.log("warning",
|
||||
"[yl_announcements] player " .. name ..
|
||||
" sent announcement: " .. param ..
|
||||
" unsuccessfully, message: " .. message)
|
||||
return false, message
|
||||
end
|
||||
end
|
||||
|
||||
@ -2,18 +2,20 @@ local chatcommand_cmd = "announcement_say_all"
|
||||
local chatcommand_definition = {
|
||||
params = "", -- Short parameter description
|
||||
description = "Say all announcements in main chat.", -- Full description
|
||||
privs = {
|
||||
[yl_announcements.settings.admin_privs] = true
|
||||
},
|
||||
privs = {[yl_announcements.settings.admin_privs] = true},
|
||||
func = function(name, param)
|
||||
local success, message = yl_announcements.chatcommand_announcement_say_all(name, param)
|
||||
local success, message =
|
||||
yl_announcements.chatcommand_announcement_say_all(name, param)
|
||||
|
||||
if success then
|
||||
minetest.log("action", "[yl_announcements] player " .. name .. " sent all announcements: " .. param)
|
||||
minetest.log("action", "[yl_announcements] player " .. name ..
|
||||
" sent all announcements: " .. param)
|
||||
return true, message
|
||||
else
|
||||
minetest.log("warning", "[yl_announcements] player " .. name .. " sent all announcements: " .. param ..
|
||||
" unsuccessfully, message: " .. message)
|
||||
minetest.log("warning",
|
||||
"[yl_announcements] player " .. name ..
|
||||
" sent all announcements: " .. param ..
|
||||
" unsuccessfully, message: " .. message)
|
||||
return false, message
|
||||
end
|
||||
end
|
||||
|
||||
203
internal.lua
203
internal.lua
@ -10,23 +10,24 @@ end
|
||||
|
||||
local function get_savepath()
|
||||
local save_path = yl_announcements.settings.save_path
|
||||
local path = yl_announcements.worldpath .. DIR_DELIM .. save_path
|
||||
local path = yl_announcements.worldpath .. DIR_DELIM .. save_path
|
||||
say("get_savepath : " .. dump(path))
|
||||
return path
|
||||
end
|
||||
|
||||
local function get_filepath(filename)
|
||||
local path_to_file = get_savepath() .. DIR_DELIM ..
|
||||
filename
|
||||
local path_to_file = get_savepath() .. DIR_DELIM .. filename
|
||||
say("get_filepath : " .. dump(filename) .. ":" .. dump(path_to_file))
|
||||
return path_to_file
|
||||
end
|
||||
|
||||
local function save_json(filename, content)
|
||||
if type(filename) ~= "string" or type(content) ~= "table" then return false end
|
||||
if type(filename) ~= "string" or type(content) ~= "table" then
|
||||
return false
|
||||
end
|
||||
local save_path = get_filepath(filename)
|
||||
local save_content = minetest.write_json(content)
|
||||
say("save_json : " .. dump(save_path) .. ":" .. dump(save_content))
|
||||
say("save_json : " .. dump(save_path) .. ":" .. dump(save_content))
|
||||
return minetest.safe_file_write(save_path, save_content)
|
||||
end
|
||||
|
||||
@ -38,12 +39,14 @@ local function load_json(path_to_file)
|
||||
file:close()
|
||||
|
||||
if not content then return false, "Error reading file: " .. path_to_file end
|
||||
say("load_json : " .. dump(path_to_file) .. ":" .. dump(content))
|
||||
say("load_json : " .. dump(path_to_file) .. ":" .. dump(content))
|
||||
return true, minetest.parse_json(content)
|
||||
end
|
||||
|
||||
-- Public functions wrap the private ones, so they can be exchanged easily
|
||||
function yl_announcements.load_json(filename, ...) return load_json(filename, ...) end
|
||||
function yl_announcements.load_json(filename, ...)
|
||||
return load_json(filename, ...)
|
||||
end
|
||||
|
||||
function yl_announcements.save_json(filename, content, ...)
|
||||
return save_json(filename, content, ...)
|
||||
@ -82,7 +85,7 @@ local function load_all_data()
|
||||
end
|
||||
end
|
||||
|
||||
yl_announcements.data = data
|
||||
yl_announcements.data = data
|
||||
|
||||
if bad == 0 then
|
||||
minetest.log("action",
|
||||
@ -121,8 +124,9 @@ function check_privs()
|
||||
if ends_with(key, "_privs") then
|
||||
local parts = split(value)
|
||||
for _, part in ipairs(parts) do
|
||||
assert(priv_exists(part), "yl_announcements : configured priv " ..
|
||||
dump(part) .. " does not exist.")
|
||||
assert(priv_exists(part),
|
||||
"yl_announcements : configured priv " .. dump(part) ..
|
||||
" does not exist.")
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -146,77 +150,67 @@ function yl_announcements.remove_file(filename) return remove_file(filename) end
|
||||
|
||||
function yl_announcements.chatcommand_announcement_add(name, param) -- param is a string containing a message and more
|
||||
|
||||
-- defense
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then
|
||||
return false, "Player not online"
|
||||
end
|
||||
if (not param) or (type(param) ~= "string") or (param == "") then
|
||||
-- defense
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then return false, "Player not online" end
|
||||
if (not param) or (type(param) ~= "string") or (param == "") then
|
||||
return false, "Requirements not met"
|
||||
end
|
||||
-- Create announcement
|
||||
local announcement = string.split(param, "$", true)
|
||||
-- Create announcement
|
||||
local announcement = string.split(param, "$", true)
|
||||
|
||||
local message = announcement[1] or ""
|
||||
local frequency = tonumber(announcement[2]) or yl_announcements.settings.frequency or 3600
|
||||
local frequency = tonumber(announcement[2]) or
|
||||
yl_announcements.settings.frequency or 3600
|
||||
local runtime = tonumber(announcement[3]) or 7257600 -- 12 weeks
|
||||
local owner = name
|
||||
|
||||
local success, announcement_id = yl_announcements.set(message, frequency, runtime, owner)
|
||||
local success, announcement_id = yl_announcements.set(message, frequency,
|
||||
runtime, owner)
|
||||
return success, "Announcement ID " .. tostring(announcement_id)
|
||||
end
|
||||
|
||||
function yl_announcements.chatcommand_announcement_copy(name, param) -- param is a numerical a_id
|
||||
|
||||
-- defense
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then
|
||||
return false, "Player not online"
|
||||
end
|
||||
if param == "" then
|
||||
return false, "Announcement ID missing"
|
||||
end
|
||||
local announcement_id = tonumber(param)
|
||||
if type(announcement_id) ~= "number" then
|
||||
return false, "Announcement ID is not a number"
|
||||
end
|
||||
-- defense
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then return false, "Player not online" end
|
||||
if param == "" then return false, "Announcement ID missing" end
|
||||
local announcement_id = tonumber(param)
|
||||
if type(announcement_id) ~= "number" then
|
||||
return false, "Announcement ID is not a number"
|
||||
end
|
||||
if (announcement_id <= 0) then
|
||||
return false, "Announcement ID cannot be zero or negative"
|
||||
end
|
||||
return false, "Announcement ID cannot be zero or negative"
|
||||
end
|
||||
|
||||
local success, formspecstring = yl_announcements.formspec(announcement_id)
|
||||
|
||||
if (success == false) then
|
||||
return false, formspecstring
|
||||
end
|
||||
if (success == false) then return false, formspecstring end
|
||||
|
||||
-- Send the formspec
|
||||
minetest.show_formspec(name, "yl_announcements:copy", formspecstring)
|
||||
-- Report
|
||||
return true, "Copied announcement ID " .. tostring(announcement_id)
|
||||
-- Send the formspec
|
||||
minetest.show_formspec(name, "yl_announcements:copy", formspecstring)
|
||||
-- Report
|
||||
return true, "Copied announcement ID " .. tostring(announcement_id)
|
||||
end
|
||||
|
||||
function yl_announcements.chatcommand_announcement_delete(name, param) -- param is a numerical a_id
|
||||
-- defense
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then
|
||||
return false, "Player not online"
|
||||
end
|
||||
if param == "" then
|
||||
return false, "Announcement ID missing"
|
||||
end
|
||||
local announcement_id = tonumber(param)
|
||||
if type(announcement_id) ~= "number" then
|
||||
return false, "Announcement ID not a number"
|
||||
end
|
||||
-- defense
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then return false, "Player not online" end
|
||||
if param == "" then return false, "Announcement ID missing" end
|
||||
local announcement_id = tonumber(param)
|
||||
if type(announcement_id) ~= "number" then
|
||||
return false, "Announcement ID not a number"
|
||||
end
|
||||
|
||||
local success, announcement = yl_announcements.delete(announcement_id)
|
||||
|
||||
if success == false then
|
||||
return false, announcement
|
||||
else
|
||||
return true, "Deleted announcement ID " .. tostring(announcement_id)
|
||||
end
|
||||
if success == false then
|
||||
return false, announcement
|
||||
else
|
||||
return true, "Deleted announcement ID " .. tostring(announcement_id)
|
||||
end
|
||||
end
|
||||
|
||||
-- List announcements
|
||||
@ -258,27 +252,26 @@ end
|
||||
|
||||
function yl_announcements.chatcommand_announcement_list_all(name, param) -- param must be empty
|
||||
-- defense
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then
|
||||
return false, "Player not online"
|
||||
end
|
||||
if param ~= "" then
|
||||
return false, "This command lists all announcements. " ..
|
||||
"Do /announcement_list <announcement_id> if you want to have only one."
|
||||
end
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then return false, "Player not online" end
|
||||
if param ~= "" then
|
||||
return false, "This command lists all announcements. " ..
|
||||
"Do /announcement_list <announcement_id> if you want to have only one."
|
||||
end
|
||||
|
||||
local success, data = yl_announcements.list()
|
||||
|
||||
if (success == false) then
|
||||
return false, data
|
||||
end
|
||||
if (success == false) then return false, data end
|
||||
|
||||
local f_announcements = {{"ID", "message", "created", "owner", "runtime", "frequency"}}
|
||||
local f_announcements = {
|
||||
{"ID", "message", "created", "owner", "runtime", "frequency"}
|
||||
}
|
||||
for _, announcement in pairs(data) do
|
||||
|
||||
local id = tostring(announcement.id) or "N/A"
|
||||
local message = announcement.message or "N/A"
|
||||
local created = os.date("!%Y-%m-%d %H:%M:%S", (announcement.creation_date or 0)) or "N/A"
|
||||
local created = os.date("!%Y-%m-%d %H:%M:%S",
|
||||
(announcement.creation_date or 0)) or "N/A"
|
||||
local owner = announcement.owner or "N/A"
|
||||
local runtime = tostring(announcement.runtime) or "N/A"
|
||||
local frequency = tostring(announcement.frequency) or "N/A"
|
||||
@ -292,17 +285,13 @@ end
|
||||
|
||||
function yl_announcements.chatcommand_announcement_list(name, param) -- param is a numerical a_id
|
||||
-- defense
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then
|
||||
return false, "Player not online"
|
||||
end
|
||||
if param == "" then
|
||||
return false, "Announcement ID missing"
|
||||
end
|
||||
local announcement_id = tonumber(param)
|
||||
if type(announcement_id) ~= "number" then
|
||||
return false, "Announcement ID not a number"
|
||||
end
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then return false, "Player not online" end
|
||||
if param == "" then return false, "Announcement ID missing" end
|
||||
local announcement_id = tonumber(param)
|
||||
if type(announcement_id) ~= "number" then
|
||||
return false, "Announcement ID not a number"
|
||||
end
|
||||
|
||||
local success, announcement = yl_announcements.get(announcement_id)
|
||||
|
||||
@ -316,27 +305,22 @@ end
|
||||
|
||||
function yl_announcements.chatcommand_announcement_say_all(name, param) -- param must be empty
|
||||
-- defense
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then
|
||||
return false, "Player not online"
|
||||
end
|
||||
if param ~= "" then
|
||||
return false, "This command sends all announcements to the main chat. " ..
|
||||
"Do /announcement_say <announcement_id> if you want to send only one."
|
||||
end
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then return false, "Player not online" end
|
||||
if param ~= "" then
|
||||
return false,
|
||||
"This command sends all announcements to the main chat. " ..
|
||||
"Do /announcement_say <announcement_id> if you want to send only one."
|
||||
end
|
||||
|
||||
local success, data = yl_announcements.list()
|
||||
|
||||
if (success == false) then
|
||||
return false, data
|
||||
end
|
||||
if (success == false) then return false, data end
|
||||
|
||||
local n = 0
|
||||
for _, announcement in pairs(data) do
|
||||
local s_success, s_message = yl_announcements.say(announcement.id, "*")
|
||||
if (s_success == false) then
|
||||
return false, s_message
|
||||
end
|
||||
if (s_success == false) then return false, s_message end
|
||||
n = n + 1
|
||||
end
|
||||
|
||||
@ -346,22 +330,17 @@ end
|
||||
|
||||
function yl_announcements.chatcommand_announcement_say(name, param) -- param is a numerical a_id
|
||||
-- defense
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then
|
||||
return false, "Player not online"
|
||||
end
|
||||
if param == "" then
|
||||
return false, "Announcement ID missing"
|
||||
end
|
||||
local announcement_id = tonumber(param)
|
||||
if type(announcement_id) ~= "number" then
|
||||
return false, "Announcement ID not a number"
|
||||
end
|
||||
|
||||
local s_success, s_message = yl_announcements.say(announcement_id, "*")
|
||||
if (s_success == false) then
|
||||
return false, s_message
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then return false, "Player not online" end
|
||||
if param == "" then return false, "Announcement ID missing" end
|
||||
local announcement_id = tonumber(param)
|
||||
if type(announcement_id) ~= "number" then
|
||||
return false, "Announcement ID not a number"
|
||||
end
|
||||
|
||||
return true, "Sent announcement ".. tostring(announcement_id) .. " to public."
|
||||
local s_success, s_message = yl_announcements.say(announcement_id, "*")
|
||||
if (s_success == false) then return false, s_message end
|
||||
|
||||
return true,
|
||||
"Sent announcement " .. tostring(announcement_id) .. " to public."
|
||||
end
|
||||
|
||||
Loading…
Reference in New Issue
Block a user