Allow email login for new users and auto-provision account on verify

This commit is contained in:
Ruslan Bakiev
2026-04-02 15:33:35 +07:00
parent 5ba87a1242
commit abf428b428

View File

@@ -52,6 +52,20 @@ function invitationToken() {
return crypto.randomBytes(24).toString('hex'); return crypto.randomBytes(24).toString('hex');
} }
function buildDefaultFullName(email) {
const localPart = email.split('@')[0]?.trim();
if (!localPart) {
return 'Новый пользователь';
}
return localPart
.replace(/[._-]+/g, ' ')
.split(' ')
.filter(Boolean)
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
.join(' ');
}
function formatOrderStatusMessage(order, status, note) { function formatOrderStatusMessage(order, status, note) {
const suffix = note ? `\nКомментарий: ${note}` : ''; const suffix = note ? `\nКомментарий: ${note}` : '';
return `Заказ ${order.code} изменил статус: ${status}.${suffix}`; return `Заказ ${order.code} изменил статус: ${status}.${suffix}`;
@@ -263,7 +277,7 @@ export const resolvers = {
throw new Error('Code login is supported only for EMAIL channel.'); throw new Error('Code login is supported only for EMAIL channel.');
} }
const destination = input.destination.trim(); const destination = input.destination.trim().toLowerCase();
if (!destination) { if (!destination) {
throw new Error('Destination is required.'); throw new Error('Destination is required.');
} }
@@ -277,12 +291,8 @@ export const resolvers = {
}, },
}); });
if (!user) {
throw new Error('User for this destination was not found.');
}
const challenge = createLoginChallenge({ const challenge = createLoginChallenge({
userId: user.id, userId: user?.id ?? null,
channel: input.channel, channel: input.channel,
destination, destination,
}); });
@@ -308,9 +318,25 @@ export const resolvers = {
code: input.code, code: input.code,
}); });
const user = await context.prisma.user.findUnique({ let user = challenge.userId
where: { id: challenge.userId }, ? await context.prisma.user.findUnique({
}); where: { id: challenge.userId },
})
: null;
if (!user && challenge.channel === 'EMAIL') {
const email = String(challenge.destination).trim().toLowerCase();
user = await context.prisma.user.upsert({
where: { email },
update: {},
create: {
email,
fullName: buildDefaultFullName(email),
role: 'CLIENT',
},
});
}
if (!user) { if (!user) {
throw new Error('User is not available for this login challenge.'); throw new Error('User is not available for this login challenge.');
} }
@@ -816,4 +842,18 @@ export const resolvers = {
RewardWithdrawalRequest: { RewardWithdrawalRequest: {
amount: (tx) => toFloat(tx.amount), amount: (tx) => toFloat(tx.amount),
}, },
User: {
company: (user, _, context) => {
if (user.company) {
return user.company;
}
if (!user.companyId) {
return null;
}
return context.prisma.company.findUnique({
where: { id: user.companyId },
});
},
},
}; };