openvibers/openvibe.mail Commits

Mail settings suggest your name; new mail goes out from it (#35)

OP OpenVibers committed 4 days ago · 936968dc90 · 3 files, +48 −0

A person's mailbox is named after their account id (01m3…@openvibe.email): private, but it reads as noise to
whoever gets mail from it, and settings showed it with nothing suggesting a real name. Until the person has a named
address, Your address now says what the mailbox address is and fills in their username (letters, numbers and single
hyphens, the server's rule) as a suggestion; they still press Create. With one, it says "You are name@…". A new
message goes out from the named address; a reply still answers from the address the mail came to.

Changes

ddiff --git a/public/js/compose.js b/public/js/compose.js
iindex 7cbd94c..69f319a 100644
---- a/public/js/compose.js
++++ b/public/js/compose.js
@@@ -26,6 +26,7 @@
addresses.forEach(function (a) { var o = node('option', a.address + (a.kind === 'mailbox' ? '' : ' · ' + a.kind)); o.value = a.address; from.appendChild(o); });
if (p.from) from.value = p.from;
else if (original.delivered_to && addresses.some(function (a) { return a.address === original.delivered_to; })) from.value = original.delivered_to;
++ else { var named = addresses.find(function (a) { return a.kind === 'name'; }); if (named) from.value = named.address; } // not the random mailbox address
field('From',from);
function addr(value) { var match = /<([^<>]+)>/.exec(value || ''); return (match ? match[1] : value || '').trim().toLowerCase(); }
var owned = addresses.map(function (a) { return a.address; });
ddiff --git a/public/js/inbox.js b/public/js/inbox.js
iindex 45f2c13..ca70b3b 100644
---- a/public/js/inbox.js
++++ b/public/js/inbox.js
@@@ -77,8 +77,22 @@
side.appendChild(ul);
var personal = el('section', 'ib-person');
personal.appendChild(el('h2', 'ib-h', 'Your address'));
++ // The mailbox is named after the account id (private, and nobody is stuck with their name), which reads as noise
++ // to whoever gets mail from it: say so, and suggest a name, until the person has one (11-09).
++ var named = addresses.find(function (a) { return a.kind === 'name'; });
++ personal.appendChild(el('p', 'ib-quiet', named
++ ? 'You are ' + named.address + '. Another name here becomes an alias of it.'
++ : 'Your mailbox\'s own address is a random one, so it says nothing about you. Pick a name people can write to; mail to it lands in this inbox.'));
var addressForm = el('form', 'ib-rule-form');
var addressName = el('input', 'ib-input'); addressName.placeholder = 'name'; addressName.required = true; addressName.setAttribute('aria-label', 'New address name');
++ if (!named) {
++ // A suggestion only (the person presses Create): their OpenVibe username, in the characters an address allows.
++ fetch('/auth/me', { credentials: 'same-origin', headers: { Accept: 'application/json' } }).then(function (r) { return r.ok ? r.json() : null; }).then(function (me) {
++ // Names are 3-32 letters, numbers or single hyphens (server/domain/person-mail.js validateName).
++ var u = me && me.user && String(me.user.username || '').toLowerCase().replace(/[._\s]+/g, '-').replace(/[^a-z0-9-]+/g, '').replace(/-+/g, '-').slice(0, 32).replace(/^-+|-+$/g, '');
++ if (u && u.length >= 3 && !addressName.value) addressName.value = u;
++ }).catch(function () { /* the field stays empty */ });
++ }
var addressDomain = el('select', 'ib-input'); addressDomain.setAttribute('aria-label', 'Address domain');
[{ domain: 'openvibe.email' }].concat(customDomains.filter(function (d) { return d.mx_verified; })).forEach(function (d) { var option = el('option', '', '@' + d.domain); option.value = d.domain; addressDomain.appendChild(option); });
var addressGo = el('button', 'ib-btn is-quiet', 'Create address'); addressGo.type = 'submit';
ddiff --git a/test/your-address.test.js b/test/your-address.test.js
nnew file mode 100644
iindex 0000000..338cc2f
---- /dev/null
++++ b/test/your-address.test.js
@@@ -0,0 +1,33 @@
++'use strict';
++const test = require('node:test');
++const assert = require('node:assert');
++const fs = require('fs');
++const path = require('path');
++
++// 11-09: a person's mailbox is named after their account id (01m3…@openvibe.email), and settings showed that with
++// nothing suggesting a real name; compose sent new mail from it. Now settings says what that address is and suggests
++// the person's username as a name, and a new message goes out from their named address when they have one.
++const inbox = fs.readFileSync(path.join(__dirname, '..', 'public', 'js', 'inbox.js'), 'utf8');
++const compose = fs.readFileSync(path.join(__dirname, '..', 'public', 'js', 'compose.js'), 'utf8');
++
++test('settings explain the random mailbox address and suggest a name', () => {
++ assert.match(inbox, /Your mailbox\\'s own address is a random one, so it says nothing about you\./);
++ assert.match(inbox, /You are ' \+ named\.address \+ '\. Another name here becomes an alias of it\./);
++ assert.match(inbox, /fetch\('\/auth\/me'/, 'the suggestion comes from the signed-in username');
++ assert.match(inbox, /if \(u && u\.length >= 3 && !addressName\.value\) addressName\.value = u;/, 'only a suggestion, never over what was typed');
++});
++
++test('the suggestion fits the server rule for names', () => {
++ const toName = (username) => String(username).toLowerCase().replace(/[._\s]+/g, '-').replace(/[^a-z0-9-]+/g, '').replace(/-+/g, '-').slice(0, 32).replace(/^-+|-+$/g, '');
++ assert.ok(inbox.includes(".replace(/[._\\s]+/g, '-').replace(/[^a-z0-9-]+/g, '').replace(/-+/g, '-').slice(0, 32).replace(/^-+|-+$/g, '')"), 'the same mapping as below');
++ assert.strictEqual(toName('ovprobe_merge_keep'), 'ovprobe-merge-keep');
++ assert.strictEqual(toName('JapaneseOldGuy'), 'japaneseoldguy');
++ assert.strictEqual(toName('__x.y__'), 'x-y');
++ ['ovprobe_merge_keep', 'JapaneseOldGuy', 'a.b.c', 'x'.repeat(40) + '_'].map(toName).forEach((n) => assert.match(n, /^[a-z0-9]+(?:-[a-z0-9]+)*$/));
++});
++
++test('a new message goes out from the named address, not the random one', () => {
++ assert.match(compose, /var named = addresses\.find\(function \(a\) \{ return a\.kind === 'name'; \}\); if \(named\) from\.value = named\.address;/);
++ const at = compose.indexOf('var named = addresses.find');
++ assert.ok(at > compose.indexOf('if (p.from) from.value = p.from;'), 'a reply still answers from the address the mail came to');
++});