mirror of
https://github.com/mt-mods/mail.git
synced 2025-07-13 09:51:58 -04:00
status refactoring
This commit is contained in:
parent
706b870b7d
commit
b414ace620
9 changed files with 91 additions and 176 deletions
13
api.lua
13
api.lua
|
@ -97,8 +97,17 @@ function mail.send(...)
|
||||||
time = os.time(),
|
time = os.time(),
|
||||||
}
|
}
|
||||||
|
|
||||||
-- insert in global storage
|
-- add in senders outbox
|
||||||
mail.addMessage(msg)
|
local entry = mail.get_storage_entry(m.from)
|
||||||
|
table.insert(entry.outbox, msg)
|
||||||
|
mail.set_storage_entry(m.from, entry)
|
||||||
|
|
||||||
|
-- add in every receivers inbox
|
||||||
|
for recipient in pairs(recipients) do
|
||||||
|
entry = mail.get_storage_entry(recipient)
|
||||||
|
table.insert(entry.inbox, msg)
|
||||||
|
mail.set_storage_entry(recipient, entry)
|
||||||
|
end
|
||||||
|
|
||||||
-- notify recipients that happen to be online
|
-- notify recipients that happen to be online
|
||||||
local mail_alert = f(mail.receive_mail_message, m.from, m.subject)
|
local mail_alert = f(mail.receive_mail_message, m.from, m.subject)
|
||||||
|
|
8
init.lua
8
init.lua
|
@ -1,9 +1,6 @@
|
||||||
mail = {
|
mail = {
|
||||||
-- api version
|
-- version
|
||||||
apiversion = 1.1,
|
version = 3,
|
||||||
|
|
||||||
-- database version
|
|
||||||
dbversion = 3.0,
|
|
||||||
|
|
||||||
-- mail directory
|
-- mail directory
|
||||||
maildir = minetest.get_worldpath().."/mails",
|
maildir = minetest.get_worldpath().."/mails",
|
||||||
|
@ -39,6 +36,7 @@ end
|
||||||
|
|
||||||
local MP = minetest.get_modpath(minetest.get_current_modname())
|
local MP = minetest.get_modpath(minetest.get_current_modname())
|
||||||
dofile(MP .. "/util/normalize.lua")
|
dofile(MP .. "/util/normalize.lua")
|
||||||
|
dofile(MP .. "/util/uuid.lua")
|
||||||
dofile(MP .. "/chatcommands.lua")
|
dofile(MP .. "/chatcommands.lua")
|
||||||
dofile(MP .. "/migrate.lua")
|
dofile(MP .. "/migrate.lua")
|
||||||
dofile(MP .. "/hud.lua")
|
dofile(MP .. "/hud.lua")
|
||||||
|
|
23
migrate.lua
23
migrate.lua
|
@ -13,12 +13,12 @@ end
|
||||||
function mail.migrate_v2_to_v3()
|
function mail.migrate_v2_to_v3()
|
||||||
minetest.mkdir(mail.maildir) -- if necessary (eg. first login)
|
minetest.mkdir(mail.maildir) -- if necessary (eg. first login)
|
||||||
print("[mail] Migration from v2 to v3 database")
|
print("[mail] Migration from v2 to v3 database")
|
||||||
local already_processed = {} -- store messages that are already process to avoid duplicates
|
|
||||||
|
|
||||||
minetest.after(0,function()
|
minetest.after(0,function()
|
||||||
for playername, _ in minetest.get_auth_handler().iterate() do
|
for playername, _ in minetest.get_auth_handler().iterate() do
|
||||||
local player_contacts = mail.read_json_file(mail.maildir .. "/contacts/" .. playername .. ".json")
|
|
||||||
local entry = mail.get_storage_entry(playername)
|
local entry = mail.get_storage_entry(playername)
|
||||||
|
|
||||||
|
local player_contacts = mail.read_json_file(mail.maildir .. "/contacts/" .. playername .. ".json")
|
||||||
for _, c in pairs(player_contacts) do
|
for _, c in pairs(player_contacts) do
|
||||||
table.insert(entry.contacts, { name = c.name, note = c.note })
|
table.insert(entry.contacts, { name = c.name, note = c.note })
|
||||||
end
|
end
|
||||||
|
@ -26,27 +26,16 @@ function mail.migrate_v2_to_v3()
|
||||||
local saneplayername = string.gsub(playername, "[.|/]", "")
|
local saneplayername = string.gsub(playername, "[.|/]", "")
|
||||||
local player_inbox = mail.read_json_file(mail.maildir .. "/" .. saneplayername .. ".json")
|
local player_inbox = mail.read_json_file(mail.maildir .. "/" .. saneplayername .. ".json")
|
||||||
for _, msg in ipairs(player_inbox) do
|
for _, msg in ipairs(player_inbox) do
|
||||||
-- id like "123456789.0singleplayer" -- it presumes that a same sender cannot send two mails within a second
|
if msg.to then
|
||||||
local msg_id = tostring(msg.time) .. msg.sender
|
table.insert(entry.inbox, {
|
||||||
local new_msg = true -- check if that mail was already processed with another player
|
id = mail.new_uuid(),
|
||||||
for _, cur_id in ipairs(already_processed) do
|
|
||||||
if cur_id == msg_id then
|
|
||||||
new_msg = false
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- add if valid and "to" field populated (missing in ancient storage formats)
|
|
||||||
if new_msg and msg.to then
|
|
||||||
local msg_table = {
|
|
||||||
sender = msg.sender,
|
sender = msg.sender,
|
||||||
to = msg.to,
|
to = msg.to,
|
||||||
cc = msg.cc,
|
cc = msg.cc,
|
||||||
subject = msg.subject,
|
subject = msg.subject,
|
||||||
body = msg.body,
|
body = msg.body,
|
||||||
time = msg.time,
|
time = msg.time,
|
||||||
}
|
})
|
||||||
mail.addMessage(msg_table)
|
|
||||||
table.insert(already_processed, msg_id)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
minetest.register_on_joinplayer(function(player)
|
minetest.register_on_joinplayer(function(player)
|
||||||
minetest.after(2, function(name)
|
minetest.after(2, function(name)
|
||||||
local messages = mail.getMessages(name)
|
local entry = mail.get_storage_entry(name)
|
||||||
|
local messages = entry.inbox
|
||||||
|
|
||||||
local unreadcount = 0
|
local unreadcount = 0
|
||||||
|
|
||||||
|
|
178
storage.lua
178
storage.lua
|
@ -59,157 +59,65 @@ function mail.set_storage_entry(playername, entry)
|
||||||
mail.storage:get_string(playername, minetest.write_json(entry))
|
mail.storage:get_string(playername, minetest.write_json(entry))
|
||||||
end
|
end
|
||||||
|
|
||||||
function mail.getMessage(msg_id)
|
-- get a mail by id from the players in- or outbox
|
||||||
local messages = mail.getMessages()
|
function mail.get_message(playername, msg_id)
|
||||||
if messages then
|
local entry = mail.get_storage_entry(playername)
|
||||||
for _, msg in ipairs(messages) do
|
for _, msg in ipairs(entry.inbox) do
|
||||||
if msg.id == msg_id then
|
if msg.id == msg_id then
|
||||||
return msg
|
return msg
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
for _, msg in ipairs(entry.outbox) do
|
||||||
|
if msg.id == msg_id then
|
||||||
|
return msg
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- api in use by the `fancyvend` mod
|
-- marks a mail read by its id
|
||||||
function mail.getMessages(playername)
|
function mail.mark_read(playername, msg_id)
|
||||||
local messages = mail.getMessages()
|
local entry = mail.get_storage_entry(playername)
|
||||||
local playerMessages = {}
|
for _, msg in ipairs(entry.inbox) do
|
||||||
if messages then
|
if msg.id == msg_id then
|
||||||
for _, msg in ipairs(messages) do
|
msg.read = true
|
||||||
local cc = ""
|
mail.set_storage_entry(playername, entry)
|
||||||
local bcc = ""
|
return
|
||||||
if msg.cc then
|
|
||||||
cc = msg.cc
|
|
||||||
end
|
|
||||||
if msg.bcc then
|
|
||||||
bcc = msg.bcc
|
|
||||||
end
|
|
||||||
local receivers = (msg.to .. "," .. cc .. "," .. bcc):split(",")
|
|
||||||
for _, receiver in ipairs(receivers) do
|
|
||||||
receiver = string.gsub(receiver, " ", "") -- avoid blank spaces (ex : " singleplayer" instead of "singleplayer")
|
|
||||||
if receiver == playername then -- check if player is a receiver
|
|
||||||
if mail.getMessageStatus(receiver, msg.id) ~= "deleted" then -- do not return if the message was deleted by player
|
|
||||||
table.insert(playerMessages, msg)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
elseif msg.sender == playername then
|
|
||||||
if mail.getMessageStatus(receiver, msg.id) ~= "deleted" then -- do not return if the message was deleted by player
|
|
||||||
table.insert(playerMessages, msg)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return playerMessages
|
|
||||||
end
|
|
||||||
|
|
||||||
function mail.getPlayerSentMessages(playername)
|
|
||||||
local messages = mail.getMessages()
|
|
||||||
local playerSentMessages = {}
|
|
||||||
if messages[1] then
|
|
||||||
for _, msg in ipairs(messages) do
|
|
||||||
if msg.sender == playername then -- check if player is the sender
|
|
||||||
-- do not return if the message was deleted from player
|
|
||||||
if mail.getMessageStatus(playername, msg.id) ~= "deleted" then
|
|
||||||
table.insert(playerSentMessages, msg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return playerSentMessages
|
|
||||||
end
|
|
||||||
|
|
||||||
function mail.setMessages(playername, messages)
|
|
||||||
if mail.write_json_file(mail.getMailFile(playername), messages) then
|
|
||||||
mail.hud_update(playername, messages)
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
minetest.log("error","[mail] Save failed - messages may be lost! ("..playername..")")
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function mail.addMessage(message)
|
|
||||||
local messages = mail.getMessages()
|
|
||||||
if messages[1] then
|
|
||||||
local previousMsg = messages[1]
|
|
||||||
message.id = previousMsg.id + 1
|
|
||||||
table.insert(messages, message)
|
|
||||||
else
|
|
||||||
message.id = 1
|
|
||||||
messages = {message}
|
|
||||||
end
|
|
||||||
if mail.write_json_file(mail.maildir .. "/mail.messages.json", messages) then
|
|
||||||
-- add default status (unread for receivers) of this message
|
|
||||||
local isSenderAReceiver = false
|
|
||||||
|
|
||||||
-- extracted maillists from all receivers
|
|
||||||
local receivers = mail.extractMaillists((message.to .. "," .. (message.cc or "")
|
|
||||||
.. "," .. (message.bcc or "")), message.sender)
|
|
||||||
|
|
||||||
for _, receiver in ipairs(receivers) do
|
|
||||||
if minetest.player_exists(receiver) then -- avoid blank names
|
|
||||||
mail.addStatus(receiver, message.id, "unread")
|
|
||||||
if message.sender == receiver then
|
|
||||||
isSenderAReceiver = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if isSenderAReceiver == false then
|
|
||||||
mail.addStatus(message.sender, message.id, "read")
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
minetest.log("error","[mail] Save failed - messages may be lost!")
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function mail.getStatus()
|
|
||||||
local messagesStatus = mail.read_json_file(mail.maildir .. "/mail.status.json")
|
|
||||||
return messagesStatus
|
|
||||||
end
|
|
||||||
|
|
||||||
function mail.getMessageStatus(player, msg_id)
|
|
||||||
local messagesStatus = mail.getStatus()
|
|
||||||
for _, msg in ipairs(messagesStatus) do
|
|
||||||
if msg.id == msg_id and msg.player == player then
|
|
||||||
return msg.status
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function mail.addStatus(player, msg_id, status)
|
-- marks a mail unread by its id
|
||||||
local messagesStatus = mail.getStatus()
|
function mail.mark_unread(playername, msg_id)
|
||||||
local msg_status = {id = msg_id, player = player, status = status}
|
local entry = mail.get_storage_entry(playername)
|
||||||
table.insert(messagesStatus, msg_status)
|
for _, msg in ipairs(entry.inbox) do
|
||||||
if mail.write_json_file(mail.maildir .. "/mail.status.json", messagesStatus) then
|
if msg.id == msg_id then
|
||||||
return true
|
msg.read = false
|
||||||
else
|
mail.set_storage_entry(playername, entry)
|
||||||
minetest.log("error","[mail] Save failed - messages status may be lost!")
|
return
|
||||||
return false
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function mail.setStatus(player, msg_id, status)
|
-- deletes a mail by its id
|
||||||
local messagesStatus = mail.getStatus()
|
function mail.delete_mail(playername, msg_id)
|
||||||
for _, msg_status in ipairs(messagesStatus) do
|
local entry = mail.get_storage_entry(playername)
|
||||||
if msg_status.id == msg_id and msg_status.player == player then
|
for i, msg in ipairs(entry.inbox) do
|
||||||
messagesStatus[_] = {id = msg_id, player = player, status = status}
|
if msg.id == msg_id then
|
||||||
|
table.remove(entry.outbox, i)
|
||||||
|
mail.set_storage_entry(playername, entry)
|
||||||
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if mail.write_json_file(mail.maildir .. "/mail.status.json", messagesStatus) then
|
for i, msg in ipairs(entry.outbox) do
|
||||||
return true
|
if msg.id == msg_id then
|
||||||
else
|
table.remove(entry.outbox, i)
|
||||||
minetest.log("error","[mail] Save failed - messages status may be lost!")
|
mail.set_storage_entry(playername, entry)
|
||||||
return false
|
return
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function mail.getContactsFile()
|
function mail.getContactsFile()
|
||||||
return mail.maildir .. "/mail.contacts.json"
|
return mail.maildir .. "/mail.contacts.json"
|
||||||
end
|
end
|
||||||
|
|
14
ui/inbox.lua
14
ui/inbox.lua
|
@ -28,7 +28,7 @@ function mail.show_inbox(name)
|
||||||
|
|
||||||
if messages[1] then
|
if messages[1] then
|
||||||
for _, message in ipairs(messages) do
|
for _, message in ipairs(messages) do
|
||||||
if mail.getMessageStatus(name, message.id) == "unread" then
|
if not message.read then
|
||||||
if not mail.player_in_list(name, message.to) then
|
if not mail.player_in_list(name, message.to) then
|
||||||
formspec[#formspec + 1] = ",#FFD788"
|
formspec[#formspec + 1] = ",#FFD788"
|
||||||
else
|
else
|
||||||
|
@ -114,9 +114,9 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
|
||||||
elseif fields.delete then
|
elseif fields.delete then
|
||||||
if formname == "mail:inbox" and messagesInbox[mail.selected_idxs.inbox[name]] then -- inbox table
|
if formname == "mail:inbox" and messagesInbox[mail.selected_idxs.inbox[name]] then -- inbox table
|
||||||
mail.setStatus(name, messagesInbox[mail.selected_idxs.inbox[name]].id, "deleted")
|
mail.delete_mail(name, messagesInbox[mail.selected_idxs.inbox[name]].id)
|
||||||
elseif formname == "mail:sent" and messagesSent[mail.selected_idxs.sent[name]] then -- sent table
|
elseif formname == "mail:sent" and messagesSent[mail.selected_idxs.sent[name]] then -- sent table
|
||||||
mail.setStatus(name, messagesSent[mail.selected_idxs.sent[name]].id, "deleted")
|
mail.delete_mail(name, messagesSent[mail.selected_idxs.sent[name]].id)
|
||||||
end
|
end
|
||||||
|
|
||||||
mail.show_mail_menu(name)
|
mail.show_mail_menu(name)
|
||||||
|
@ -150,18 +150,18 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
|
||||||
elseif fields.markread then
|
elseif fields.markread then
|
||||||
if formname == "mail:inbox" and messagesInbox[mail.selected_idxs.inbox[name]] then
|
if formname == "mail:inbox" and messagesInbox[mail.selected_idxs.inbox[name]] then
|
||||||
mail.setStatus(name, messagesInbox[mail.selected_idxs.inbox[name]].id, "read")
|
mail.mark_read(name, messagesInbox[mail.selected_idxs.inbox[name]].id)
|
||||||
elseif formname == "mail:sent" and messagesSent[mail.selected_idxs.sent[name]] then
|
elseif formname == "mail:sent" and messagesSent[mail.selected_idxs.sent[name]] then
|
||||||
mail.setStatus(name, messagesSent[mail.selected_idxs.sent[name]].id, "read")
|
mail.mark_read(name, messagesSent[mail.selected_idxs.sent[name]].id)
|
||||||
end
|
end
|
||||||
|
|
||||||
mail.show_mail_menu(name)
|
mail.show_mail_menu(name)
|
||||||
|
|
||||||
elseif fields.markunread then
|
elseif fields.markunread then
|
||||||
if formname == "mail:inbox" and messagesInbox[mail.selected_idxs.inbox[name]] then
|
if formname == "mail:inbox" and messagesInbox[mail.selected_idxs.inbox[name]] then
|
||||||
mail.setStatus(name, messagesInbox[mail.selected_idxs.inbox[name]].id, "unread")
|
mail.mark_unread(name, messagesInbox[mail.selected_idxs.inbox[name]].id)
|
||||||
elseif formname == "mail:sent" and messagesSent[mail.selected_idxs.sent[name]] then
|
elseif formname == "mail:sent" and messagesSent[mail.selected_idxs.sent[name]] then
|
||||||
mail.setStatus(name, messagesSent[mail.selected_idxs.sent[name]].id, "unread")
|
mail.mark_unread(name, messagesSent[mail.selected_idxs.sent[name]].id)
|
||||||
end
|
end
|
||||||
|
|
||||||
mail.show_mail_menu(name)
|
mail.show_mail_menu(name)
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
local FORMNAME = "mail:message"
|
local FORMNAME = "mail:message"
|
||||||
|
|
||||||
function mail.show_message(name, msgnumber)
|
function mail.show_message(name, id)
|
||||||
local message = mail.getMessage(msgnumber)
|
local message = mail.get_message(name, id)
|
||||||
|
|
||||||
local formspec = [[
|
local formspec = [[
|
||||||
size[8,9]
|
size[8,9]
|
||||||
|
|
||||||
|
@ -32,10 +33,9 @@ function mail.show_message(name, msgnumber)
|
||||||
local body = minetest.formspec_escape(message.body) or ""
|
local body = minetest.formspec_escape(message.body) or ""
|
||||||
formspec = string.format(formspec, from, to, cc, date, subject, body)
|
formspec = string.format(formspec, from, to, cc, date, subject, body)
|
||||||
|
|
||||||
local message_status = mail.getMessageStatus(name, message.id)
|
if not message.read then
|
||||||
|
-- mark as read
|
||||||
if message_status == "unread" then
|
mail.mark_read(name, id)
|
||||||
mail.setStatus(name, message.id, "read")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
minetest.show_formspec(name, FORMNAME, formspec)
|
minetest.show_formspec(name, FORMNAME, formspec)
|
||||||
|
@ -125,9 +125,9 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
|
||||||
elseif fields.delete then
|
elseif fields.delete then
|
||||||
if messagesInbox[mail.selected_idxs.inbox[name]] then
|
if messagesInbox[mail.selected_idxs.inbox[name]] then
|
||||||
mail.setStatus(name, messagesInbox[mail.selected_idxs.inbox[name]].id, "deleted")
|
mail.delete_mail(name, messagesInbox[mail.selected_idxs.inbox[name]].id)
|
||||||
elseif messagesSent[mail.selected_idxs.sent[name]] then
|
elseif messagesSent[mail.selected_idxs.sent[name]] then
|
||||||
mail.setStatus(name, messagesSent[mail.selected_idxs.sent[name]].id, "deleted")
|
mail.delete_mail(name, messagesSent[mail.selected_idxs.sent[name]].id)
|
||||||
end
|
end
|
||||||
mail.show_mail_menu(name)
|
mail.show_mail_menu(name)
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,7 +19,8 @@ local sent_formspec = "size[8,10;]" .. mail.theme .. [[
|
||||||
|
|
||||||
function mail.show_sent(name)
|
function mail.show_sent(name)
|
||||||
local formspec = { sent_formspec }
|
local formspec = { sent_formspec }
|
||||||
local messages = mail.getPlayerSentMessages(name)
|
local entry = mail.get_storage_entry(name)
|
||||||
|
local messages = entry.outbox
|
||||||
|
|
||||||
mail.message_drafts[name] = nil
|
mail.message_drafts[name] = nil
|
||||||
|
|
||||||
|
|
9
util/uuid.lua
Normal file
9
util/uuid.lua
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
-- source: https://gist.github.com/jrus/3197011
|
||||||
|
local random = math.random
|
||||||
|
function mail.new_uuid()
|
||||||
|
local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
|
||||||
|
return string.gsub(template, '[xy]', function (c)
|
||||||
|
local v = (c == 'x') and random(0, 0xf) or random(8, 0xb)
|
||||||
|
return string.format('%x', v)
|
||||||
|
end)
|
||||||
|
end
|
Loading…
Add table
Add a link
Reference in a new issue