Compare commits

...

10 Commits

Author SHA1 Message Date
Athozus
8a992b7a29
Bump version to 1.5.0-dev in about.lua 2024-09-01 16:41:39 +02:00
Maksym H.
1bffd98132 Localize get_translator call 2024-09-01 16:36:55 +02:00
Athozus
59667bd35c
Add 5.9.0 to workflows 2024-08-12 00:33:36 +02:00
Athozus
09b233b039
Update credits and bump to version 1.4.1
Some checks are pending
luacheck / luacheck (push) Waiting to run
test / build (5.8.0) (push) Waiting to run
test / build (latest) (push) Waiting to run
test / build (5.0.1) (push) Waiting to run
test / build (5.1.1) (push) Waiting to run
test / build (5.2.0) (push) Waiting to run
test / build (5.3.0) (push) Waiting to run
test / build (5.4.1) (push) Waiting to run
test / build (5.5.1) (push) Waiting to run
test / build (5.6.1) (push) Waiting to run
test / build (5.7.0) (push) Waiting to run
2024-08-09 00:35:42 +02:00
Athozus
b9982f11e6
Add support for a get_keys() equivalent for lower than 5.7 Minetest versions (#153)
* Add support for a get_keys() equivalent for lower than 5.7 Minetest versions

* Do not call the function itself to check if it exists

Co-authored-by: luk3yx <luk3yx@users.noreply.github.com>

* Do not call the function itself to check if it exists (2)

Co-authored-by: luk3yx <luk3yx@users.noreply.github.com>

* Fix an occurrence of get_keys() in is_uuid_existing()

---------

Co-authored-by: luk3yx <luk3yx@users.noreply.github.com>
2024-08-09 00:31:28 +02:00
Athozus
4f15c2fe65
Update version to 1.4.1-dev in about.lua 2024-08-06 02:26:10 +02:00
1F616EMO
4cd06c5f5f Optimize performance of the inbox
Moves the `mail.get_setting(name, "mute_list")` call out of the message loop. Previously, this is called repeated, causing disastrous lag when using mail with beerchat.
2024-08-06 02:21:20 +02:00
Athozus
036d37695a
Update files to 1.4 (#149)
* Update README and screenshots

* Update version number in about.lua
2024-08-05 17:23:01 +02:00
Athozus
5cfec3a92a
Update api.md docs (#148)
* Update player entry format in API documentation

* Add spam flag
2024-08-05 17:01:20 +02:00
Athozus
a347a79e6a
Update actions workflows 2024-08-05 16:59:51 +02:00
28 changed files with 136 additions and 73 deletions

View File

@ -9,9 +9,9 @@ jobs:
timeout-minutes: 10 timeout-minutes: 10
strategy: strategy:
matrix: matrix:
ENGINE_VERSION: [5.0.1, 5.1.1, 5.2.0, 5.3.0, 5.4.1, 5.5.1, 5.6.1, 5.7.0, 5.8.0, latest] ENGINE_VERSION: [5.0.1, 5.1.1, 5.2.0, 5.3.0, 5.4.1, 5.5.1, 5.6.1, 5.7.0, 5.8.0, 5.9.0, latest]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: test - name: test
run: docker-compose up --exit-code-from sut run: docker compose up --exit-code-from sut

View File

@ -11,7 +11,8 @@ It adds a mail-system that allows players to send each other messages in-game an
# Screenshot # Screenshot
![](screenshot_1.2.0.png) ![Main view](screenshot_1.4.0_1.png)
![Message view](screenshot_1.4.0_2.png)
# Installation # Installation
@ -43,7 +44,8 @@ Mails can be deleted, marked as read or unread, replied to and forwarded to anot
* Multiple selection (new in 1.1.0) * Multiple selection (new in 1.1.0)
* Settings * Settings
* Chat, on join, HUD and sound notifications * Chat, on join, HUD and sound notifications
* Translated in : English, French, German, Chinese (both traditional and simplified), Spanish, Brazilian Portuguese. * Anti-spam detection
* Translated in : English, French, German, Chinese (both traditional and simplified), Spanish, Brazilian Portuguese, Hungarian, Indonesian.
# Compatibility / Migration # Compatibility / Migration
@ -51,8 +53,10 @@ Overview:
* `v1` all the data is in the `<worldfolder>/mails.db` file * `v1` all the data is in the `<worldfolder>/mails.db` file
* `v2` every player has its own (in-) mailbox in the `<worldfolder>/mails/<playername>.json` file * `v2` every player has its own (in-) mailbox in the `<worldfolder>/mails/<playername>.json` file
* `v3` every player has an entry in the `<playername>` `mod_storage/` (inbox, outbox, drafts, contacts, mailing lists, settings) * `v3` every player has an entry in the `<playername>` `mod_storage/` (inbox, outbox, drafts, contacts, mailing lists, settings)
* `v3.1` database fix after the message id mess
# Dependencies # Dependencies
* None * None
# License # License
@ -72,7 +76,7 @@ See the "LICENSE" file
* fluxionary (Minor fixups) * fluxionary (Minor fixups)
* Toby1710 (UX fixes) * Toby1710 (UX fixes)
* Peter Nerlich (CC, BCC) * Peter Nerlich (CC, BCC)
* Emojigit (Traditional Chinese translation) * Emojigit (Performance, Traditional Chinese translation)
* Niklp09 (German translation) * Niklp09 (German translation)
* Dennis Jenkins (UX fixes) * Dennis Jenkins (UX fixes)
* Thomas Rudin (Maintenance) * Thomas Rudin (Maintenance)
@ -84,7 +88,12 @@ See the "LICENSE" file
* nyomi (Hungarian translation) * nyomi (Hungarian translation)
* whosit (UI fixes) * whosit (UI fixes)
* Wuzzy (German translation) * Wuzzy (German translation)
* savilli (UX fixes)
* Panquesito7 (Maintenance)
* Eredin (Spanish translation)
* Muhammad Rifqi Priyo Susanto (Indonesian translation) * Muhammad Rifqi Priyo Susanto (Indonesian translation)
* aBlueShadow (sfinv compatibility)
* Singularis (UX and storage fixes)
# Contribute # Contribute

View File

@ -1,7 +1,7 @@
-- see: mail.md -- see: mail.md
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
local f = string.format local f = string.format

17
api.md
View File

@ -1,4 +1,3 @@
# Mail format # Mail format
The mail format in the api hooks The mail format in the api hooks
@ -70,6 +69,7 @@ The recipient handler should return
mod-storage entry for a player (indexed by playername and serialized with json): mod-storage entry for a player (indexed by playername and serialized with json):
```lua ```lua
{ {
contacts = { contacts = {
{ {
-- name of the player (unique key in the list) -- name of the player (unique key in the list)
@ -99,7 +99,9 @@ mod-storage entry for a player (indexed by playername and serialized with json):
-- timestamp (os.time()) -- timestamp (os.time())
time = 1234, time = 1234,
-- read-flag (true: player has read the mail, inbox only) -- read-flag (true: player has read the mail, inbox only)
read = true read = true,
-- spam-flag (true: that mail is noted as a spam)
spam = false
},{ },{
... ...
} }
@ -107,6 +109,12 @@ mod-storage entry for a player (indexed by playername and serialized with json):
outbox = { outbox = {
-- same format as "inbox" -- same format as "inbox"
}, },
drafts = {
-- same format as "inbox"
},
trash = {
-- same format as "inbox"
},
lists = { lists = {
{ {
-- name of the maillist (unique key in the list) -- name of the maillist (unique key in the list)
@ -116,5 +124,10 @@ mod-storage entry for a player (indexed by playername and serialized with json):
-- playername list -- playername list
players = {"playername", "playername2"} players = {"playername", "playername2"}
} }
},
settings = {
setting1 = "value",
setting2 = true,
setting3 = 123
} }
} }

View File

@ -1,4 +1,4 @@
version: "3.6" version: "4.1"
services: services:
sut: sut:
@ -16,4 +16,4 @@ services:
- "30000:30000/udp" - "30000:30000/udp"
volumes: volumes:
world_data: {} world_data: {}

View File

@ -5,6 +5,9 @@ mail = {
-- mod storage -- mod storage
storage = minetest.get_mod_storage(), storage = minetest.get_mod_storage(),
-- translation
S = minetest.get_translator(minetest.get_current_modname()),
-- ui theme prepend -- ui theme prepend
theme = "", theme = "",

View File

@ -91,17 +91,29 @@ local function search_box(playername, box, uuid)
return false return false
end end
local function search_boxes(playername, boxes, uuid)
local result
for _, b in ipairs(boxes) do
result = search_box(playername, b, uuid)
if result then return result end
end
end
local function is_uuid_existing(uuid) local function is_uuid_existing(uuid)
for _, k in ipairs(mail.storage:get_keys()) do local boxes = {"inbox", "outbox", "drafts", "trash"}
if string.sub(k,1,5) == "mail/" then if mail.storage.get_keys then
local p = string.sub(k, 6) for _, k in ipairs(mail.storage:get_keys()) do
local result if string.sub(k,1,5) == "mail/" then
local boxes = {"inbox", "outbox", "drafts", "trash"} local p = string.sub(k, 6)
for _, b in ipairs(boxes) do local result = search_boxes(p, boxes, uuid)
result = search_box(p, b, uuid)
if result then return result end if result then return result end
end end
end end
else
for p, _ in minetest.get_auth_handler().iterate() do
local result = search_boxes(p, boxes, uuid)
if result then return result end
end
end end
return false return false
end end
@ -116,55 +128,78 @@ local function are_message_sames(a, b)
and a.body == b.body and a.body == b.body
end end
local function fix_duplicate_uuids(playername, box) local function replace_other_player_message_uuid(p, m, uuid, new_uuid)
local er = mail.get_storage_entry(p)
for _, r in ipairs(er.inbox) do
if r.id == uuid and not are_message_sames(m, r) then
r.id = new_uuid
end
end
for _, r in ipairs(er.outbox) do
if r.id == uuid and not are_message_sames(m, r) then
r.id = new_uuid
end
end
for _, r in ipairs(er.drafts) do
if r.id == uuid and not are_message_sames(m, r) then
r.id = new_uuid
end
end
for _, r in ipairs(er.trash) do
if r.id == uuid and not are_message_sames(m, r) then
r.id = new_uuid
end
end
mail.set_storage_entry(p, er)
end
local function fix_box_duplicate_uuids(playername, box)
local e = mail.get_storage_entry(playername) local e = mail.get_storage_entry(playername)
for _, m in ipairs(e[box]) do for _, m in ipairs(e[box]) do
local uuid = m.id local uuid = m.id
local exists = is_uuid_existing(uuid) local exists = is_uuid_existing(uuid)
if exists and not are_message_sames(exists, m) then if exists and not are_message_sames(exists, m) then
local new_uuid = mail.new_uuid() -- generates a new uuid to replace doublons local new_uuid = mail.new_uuid() -- generates a new uuid to replace doublons
for _, k in ipairs(mail.storage:get_keys()) do if mail.storage.get_keys then
if string.sub(k,1,5) == "mail/" then for _, k in ipairs(mail.storage:get_keys()) do
local p = string.sub(k, 6) if string.sub(k,1,5) == "mail/" then
local er = mail.get_storage_entry(p) local p = string.sub(k, 6)
for _, r in ipairs(er.inbox) do replace_other_player_message_uuid(p, m, uuid, new_uuid)
if r.id == uuid and not are_message_sames(m, r) then
r.id = new_uuid
end
end end
for _, r in ipairs(er.outbox) do end
if r.id == uuid and not are_message_sames(m, r) then else
r.id = new_uuid for p, _ in minetest.get_auth_handler().iterate() do
end replace_other_player_message_uuid(p, m, uuid, new_uuid)
end
for _, r in ipairs(er.drafts) do
if r.id == uuid and not are_message_sames(m, r) then
r.id = new_uuid
end
end
for _, r in ipairs(er.trash) do
if r.id == uuid and not are_message_sames(m, r) then
r.id = new_uuid
end
end
mail.set_storage_entry(p, er)
end end
end end
end end
end end
end end
local function fix_player_duplicate_uuids(playername)
fix_box_duplicate_uuids(playername, "inbox")
fix_box_duplicate_uuids(playername, "outbox")
fix_box_duplicate_uuids(playername, "drafts")
fix_box_duplicate_uuids(playername, "trash")
end
-- repair database for uuid doublons -- repair database for uuid doublons
local function repair_storage() local function repair_storage()
-- iterate through players -- iterate through players
for _, k in ipairs(mail.storage:get_keys()) do -- get_keys() was introduced in 5.7
if string.sub(k,1,5) == "mail/" then if mail.storage.get_keys then
local p = string.sub(k, 6) for _, k in ipairs(mail.storage:get_keys()) do
fix_duplicate_uuids(p, "inbox") if string.sub(k,1,5) == "mail/" then
fix_duplicate_uuids(p, "outbox") local p = string.sub(k, 6)
fix_duplicate_uuids(p, "drafts") fix_player_duplicate_uuids(p)
fix_duplicate_uuids(p, "trash") end
end end
else
minetest.after(0, function()
for p, _ in minetest.get_auth_handler().iterate() do
fix_player_duplicate_uuids(p)
end
end)
end end
end end

View File

@ -1,5 +1,5 @@
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
minetest.after(2, function(name) minetest.after(2, function(name)

View File

@ -1,4 +1,6 @@
local S = minetest.get_translator("mail") -- translation
local S = mail.S
local has_canonical_name = minetest.get_modpath("canonical_name") local has_canonical_name = minetest.get_modpath("canonical_name")
mail.register_on_player_receive(function(name, msg) mail.register_on_player_receive(function(name, msg)

BIN
screenshot_1.4.0_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 722 KiB

BIN
screenshot_1.4.0_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 KiB

View File

@ -1,5 +1,5 @@
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
local FORMNAME = "mail:about" local FORMNAME = "mail:about"
@ -19,7 +19,7 @@ local contributors = {
{ name = "BuckarooBanzay", groups = {"c"} }, { name = "BuckarooBanzay", groups = {"c"} },
{ name = "Chache", groups = {"i"} }, { name = "Chache", groups = {"i"} },
{ name = "Dennis Jenkins", groups = {"c"} }, { name = "Dennis Jenkins", groups = {"c"} },
{ name = "Emojigit", groups = {"i"} }, { name = "Emojigit", groups = {"c", "i"} },
{ name = "Eredin", groups = {"i"} }, { name = "Eredin", groups = {"i"} },
{ name = "fluxionary", groups = {"c"} }, { name = "fluxionary", groups = {"c"} },
{ name = "imre84", groups = {"c"} }, { name = "imre84", groups = {"c"} },
@ -55,7 +55,7 @@ function mail.show_about(name)
label[0.2,0;Mail] label[0.2,0;Mail]
label[0.2,0.5;]] .. S("Provided by mt-mods") .. [[] label[0.2,0.5;]] .. S("Provided by mt-mods") .. [[]
label[0.2,0.9;]] .. S("Version: @1", "1.4.0-dev") .. [[] label[0.2,0.9;]] .. S("Version: @1", "1.5.0-dev") .. [[]
box[0,1.5;3,0.45;]] .. mail.get_color("highlighted") .. [[] box[0,1.5;3,0.45;]] .. mail.get_color("highlighted") .. [[]
label[0.2,1.5;]] .. S("Licenses") .. [[] label[0.2,1.5;]] .. S("Licenses") .. [[]

View File

@ -1,5 +1,5 @@
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
local FORMNAME = "mail:compose" local FORMNAME = "mail:compose"

View File

@ -1,5 +1,5 @@
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
local FORMNAME = "mail:contacts" local FORMNAME = "mail:contacts"

View File

@ -1,6 +1,5 @@
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
function mail.show_drafts(name) function mail.show_drafts(name)
local trash_tab = "" local trash_tab = ""

View File

@ -1,5 +1,5 @@
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
local FORMNAME = "mail:editcontact" local FORMNAME = "mail:editcontact"

View File

@ -1,5 +1,5 @@
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
local FORMNAME = "mail:editmaillist" local FORMNAME = "mail:editmaillist"

View File

@ -1,5 +1,5 @@
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
function mail.show_inbox(name, sortfieldindex, sortdirection, filter) function mail.show_inbox(name, sortfieldindex, sortdirection, filter)
sortfieldindex = tonumber(sortfieldindex or mail.selected_idxs.sortfield[name]) sortfieldindex = tonumber(sortfieldindex or mail.selected_idxs.sortfield[name])
@ -77,6 +77,7 @@ function mail.show_inbox(name, sortfieldindex, sortdirection, filter)
local unread_color_enable = mail.get_setting(name, "unreadcolorenable") local unread_color_enable = mail.get_setting(name, "unreadcolorenable")
local cc_color_enable = mail.get_setting(name, "cccolorenable") local cc_color_enable = mail.get_setting(name, "cccolorenable")
local mute_list = mail.get_setting(name, "mute_list")
if #messages > 0 then if #messages > 0 then
for _, message in ipairs(messages) do for _, message in ipairs(messages) do
@ -103,7 +104,7 @@ function mail.show_inbox(name, sortfieldindex, sortdirection, filter)
if message.spam then if message.spam then
table.insert(displayed_color, "warning") table.insert(displayed_color, "warning")
end end
if table.indexof(mail.get_setting(name, "mute_list"), message.from) >= 1 then if table.indexof(mute_list, message.from) >= 1 then
table.insert(displayed_color, "muted") table.insert(displayed_color, "muted")
end end
formspec[#formspec + 1] = "," .. mail.get_color(displayed_color) formspec[#formspec + 1] = "," .. mail.get_color(displayed_color)

View File

@ -1,5 +1,5 @@
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
local FORMNAME = "mail:maillists" local FORMNAME = "mail:maillists"

View File

@ -1,5 +1,5 @@
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
local FORMNAME = "mail:message" local FORMNAME = "mail:message"

View File

@ -1,5 +1,5 @@
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
function mail.show_outbox(name, sortfieldindex, sortdirection, filter) function mail.show_outbox(name, sortfieldindex, sortdirection, filter)
sortfieldindex = tonumber(sortfieldindex or mail.selected_idxs.sortfield[name]) sortfieldindex = tonumber(sortfieldindex or mail.selected_idxs.sortfield[name])

View File

@ -1,5 +1,5 @@
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
local FORMNAME = "mail:selectcontact" local FORMNAME = "mail:selectcontact"

View File

@ -1,5 +1,5 @@
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
local FORMNAME = "mail:settings" local FORMNAME = "mail:settings"

View File

@ -1,5 +1,5 @@
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
local trash_formspec = "size[8.5,11;]" .. mail.theme .. [[ local trash_formspec = "size[8.5,11;]" .. mail.theme .. [[
tabheader[0.3,1;boxtab;]] .. tabheader[0.3,1;boxtab;]] ..

View File

@ -1,5 +1,5 @@
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
function mail.compile_contact_list(name, selected, playernames) function mail.compile_contact_list(name, selected, playernames)
-- TODO: refactor this - not just compiles *a* list, but *the* list for the contacts screen (too inflexible) -- TODO: refactor this - not just compiles *a* list, but *the* list for the contacts screen (too inflexible)

View File

@ -1,4 +1,5 @@
local S = minetest.get_translator("mail") -- translation
local S = mail.S
local function recursive_expand_recipient_names(sender, list, is_toplevel, recipients, undeliverable) local function recursive_expand_recipient_names(sender, list, is_toplevel, recipients, undeliverable)
for _, name in ipairs(list) do for _, name in ipairs(list) do

View File

@ -1,5 +1,5 @@
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
mail.settings = { mail.settings = {
chat_notifications = { chat_notifications = {

View File

@ -1,5 +1,5 @@
-- translation -- translation
local S = minetest.get_translator("mail") local S = mail.S
function mail.time_ago(t) function mail.time_ago(t)
local elapsed = os.time() - t local elapsed = os.time() - t