Expose manager telegram avatars
This commit is contained in:
99
src/access.js
Normal file
99
src/access.js
Normal file
@@ -0,0 +1,99 @@
|
||||
export const MANAGER_ROLES = ['MANAGER', 'SUPER_MANAGER'];
|
||||
const NO_CLIENT_IDS = ['__no_managed_clients__'];
|
||||
|
||||
export function isSuperManager(user) {
|
||||
return user?.role === 'SUPER_MANAGER';
|
||||
}
|
||||
|
||||
export function isManagerRole(role) {
|
||||
return MANAGER_ROLES.includes(role);
|
||||
}
|
||||
|
||||
function normalizeManagedClientIds(clientIds) {
|
||||
if (clientIds == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return clientIds.length ? clientIds : NO_CLIENT_IDS;
|
||||
}
|
||||
|
||||
export async function getManagedClientIds(prisma, manager) {
|
||||
if (isSuperManager(manager)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [managedOrders, acceptedInvitations, reviewedRequests, reviewedWithdrawals] = await Promise.all([
|
||||
prisma.order.findMany({
|
||||
where: { managerId: manager.id },
|
||||
select: { customerId: true },
|
||||
}),
|
||||
prisma.invitation.findMany({
|
||||
where: {
|
||||
managerId: manager.id,
|
||||
acceptedById: { not: null },
|
||||
},
|
||||
select: { acceptedById: true },
|
||||
}),
|
||||
prisma.registrationRequest.findMany({
|
||||
where: {
|
||||
reviewedById: manager.id,
|
||||
requesterId: { not: null },
|
||||
},
|
||||
select: { requesterId: true },
|
||||
}),
|
||||
prisma.rewardWithdrawalRequest.findMany({
|
||||
where: { reviewedById: manager.id },
|
||||
select: { requesterId: true },
|
||||
}),
|
||||
]);
|
||||
|
||||
const clientIds = new Set();
|
||||
|
||||
for (const order of managedOrders) {
|
||||
if (order.customerId) {
|
||||
clientIds.add(order.customerId);
|
||||
}
|
||||
}
|
||||
|
||||
for (const invitation of acceptedInvitations) {
|
||||
if (invitation.acceptedById) {
|
||||
clientIds.add(invitation.acceptedById);
|
||||
}
|
||||
}
|
||||
|
||||
for (const request of reviewedRequests) {
|
||||
if (request.requesterId) {
|
||||
clientIds.add(request.requesterId);
|
||||
}
|
||||
}
|
||||
|
||||
for (const withdrawal of reviewedWithdrawals) {
|
||||
if (withdrawal.requesterId) {
|
||||
clientIds.add(withdrawal.requesterId);
|
||||
}
|
||||
}
|
||||
|
||||
return [...clientIds];
|
||||
}
|
||||
|
||||
export async function getManagedClientUserWhere(prisma, manager) {
|
||||
const managedClientIds = normalizeManagedClientIds(await getManagedClientIds(prisma, manager));
|
||||
|
||||
if (managedClientIds == null) {
|
||||
return { role: 'CLIENT' };
|
||||
}
|
||||
|
||||
return {
|
||||
role: 'CLIENT',
|
||||
id: { in: managedClientIds },
|
||||
};
|
||||
}
|
||||
|
||||
export async function canManagerAccessUser(prisma, manager, userId) {
|
||||
if (isSuperManager(manager) || userId === manager.id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const managedClientIds = await getManagedClientIds(prisma, manager);
|
||||
return managedClientIds.includes(userId);
|
||||
}
|
||||
113
src/resolvers.js
113
src/resolvers.js
@@ -8,14 +8,19 @@ import {
|
||||
maskAuthDestination,
|
||||
verifyLoginChallengeCode,
|
||||
} from './auth.js';
|
||||
import {
|
||||
MANAGER_ROLES,
|
||||
canManagerAccessUser,
|
||||
getManagedClientUserWhere,
|
||||
isManagerRole,
|
||||
isSuperManager,
|
||||
} from './access.js';
|
||||
import { sendLoginCodeEmail } from './mailer.js';
|
||||
import { dispatchToUserConnections, sendMessengerMessage } from './messenger.js';
|
||||
import { dateTimeScalar, jsonScalar } from './scalars.js';
|
||||
import { fetchTelegramConnectionProfile } from './telegram.js';
|
||||
|
||||
const ACTIVE_ORDER_STATUSES = ['NEW', 'MANAGER_PROCESSING', 'WAITING_DOUBLE_CONFIRM', 'CONFIRMED', 'IN_PROGRESS'];
|
||||
const MANAGER_ROLES = ['MANAGER', 'SUPER_MANAGER'];
|
||||
const NO_CLIENT_IDS = ['__no_managed_clients__'];
|
||||
|
||||
function toFloat(value) {
|
||||
return value == null ? null : Number(value);
|
||||
@@ -40,101 +45,8 @@ function requireManagerAccess(context) {
|
||||
return requireAnyRole(context, MANAGER_ROLES);
|
||||
}
|
||||
|
||||
function isSuperManager(user) {
|
||||
return user.role === 'SUPER_MANAGER';
|
||||
}
|
||||
|
||||
function isManagerRole(role) {
|
||||
return MANAGER_ROLES.includes(role);
|
||||
}
|
||||
|
||||
function normalizeManagedClientIds(clientIds) {
|
||||
if (clientIds == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return clientIds.length ? clientIds : NO_CLIENT_IDS;
|
||||
}
|
||||
|
||||
async function getManagedClientIds(prisma, manager) {
|
||||
if (isSuperManager(manager)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const [managedOrders, acceptedInvitations, reviewedRequests, reviewedWithdrawals] = await Promise.all([
|
||||
prisma.order.findMany({
|
||||
where: { managerId: manager.id },
|
||||
select: { customerId: true },
|
||||
}),
|
||||
prisma.invitation.findMany({
|
||||
where: {
|
||||
managerId: manager.id,
|
||||
acceptedById: { not: null },
|
||||
},
|
||||
select: { acceptedById: true },
|
||||
}),
|
||||
prisma.registrationRequest.findMany({
|
||||
where: {
|
||||
reviewedById: manager.id,
|
||||
requesterId: { not: null },
|
||||
},
|
||||
select: { requesterId: true },
|
||||
}),
|
||||
prisma.rewardWithdrawalRequest.findMany({
|
||||
where: { reviewedById: manager.id },
|
||||
select: { requesterId: true },
|
||||
}),
|
||||
]);
|
||||
|
||||
const clientIds = new Set();
|
||||
|
||||
for (const order of managedOrders) {
|
||||
if (order.customerId) {
|
||||
clientIds.add(order.customerId);
|
||||
}
|
||||
}
|
||||
|
||||
for (const invitation of acceptedInvitations) {
|
||||
if (invitation.acceptedById) {
|
||||
clientIds.add(invitation.acceptedById);
|
||||
}
|
||||
}
|
||||
|
||||
for (const request of reviewedRequests) {
|
||||
if (request.requesterId) {
|
||||
clientIds.add(request.requesterId);
|
||||
}
|
||||
}
|
||||
|
||||
for (const withdrawal of reviewedWithdrawals) {
|
||||
if (withdrawal.requesterId) {
|
||||
clientIds.add(withdrawal.requesterId);
|
||||
}
|
||||
}
|
||||
|
||||
return [...clientIds];
|
||||
}
|
||||
|
||||
async function getManagedClientUserWhere(prisma, manager) {
|
||||
const managedClientIds = normalizeManagedClientIds(await getManagedClientIds(prisma, manager));
|
||||
|
||||
if (managedClientIds == null) {
|
||||
return { role: 'CLIENT' };
|
||||
}
|
||||
|
||||
return {
|
||||
role: 'CLIENT',
|
||||
id: { in: managedClientIds },
|
||||
};
|
||||
}
|
||||
|
||||
async function assertManagerCanAccessUser(prisma, manager, userId) {
|
||||
if (isSuperManager(manager) || userId === manager.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const managedClientIds = await getManagedClientIds(prisma, manager);
|
||||
if (!managedClientIds.includes(userId)) {
|
||||
if (!await canManagerAccessUser(prisma, manager, userId)) {
|
||||
throw new Error('User is not available for this manager.');
|
||||
}
|
||||
}
|
||||
@@ -594,6 +506,14 @@ export const resolvers = {
|
||||
const users = await context.prisma.user.findMany({
|
||||
where: managedUsersWhere,
|
||||
include: {
|
||||
messengerConnections: {
|
||||
where: {
|
||||
type: 'TELEGRAM',
|
||||
isActive: true,
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
take: 1,
|
||||
},
|
||||
counterpartyProfile: {
|
||||
select: {
|
||||
companyName: true,
|
||||
@@ -626,6 +546,7 @@ export const resolvers = {
|
||||
createdAt: user.createdAt,
|
||||
orderCount: user._count.clientOrders,
|
||||
lastOrderAt: user.clientOrders[0]?.createdAt ?? null,
|
||||
telegramConnection: user.messengerConnections[0] ?? null,
|
||||
}));
|
||||
},
|
||||
|
||||
|
||||
@@ -147,6 +147,7 @@ type ManagerUser {
|
||||
createdAt: DateTime!
|
||||
orderCount: Int!
|
||||
lastOrderAt: DateTime
|
||||
telegramConnection: MessengerConnection
|
||||
}
|
||||
|
||||
type MessengerConnection {
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
issueTemporaryLoginToken,
|
||||
verifyAccessToken,
|
||||
} from './auth.js';
|
||||
import { canManagerAccessUser, isManagerRole } from './access.js';
|
||||
import { buildContext } from './context.js';
|
||||
import { sendMessengerMessage } from './messenger.js';
|
||||
import { prisma } from './prisma-client.js';
|
||||
@@ -258,12 +259,29 @@ app.get('/messenger/avatar/:connectionId', async (req, res) => {
|
||||
const connection = await prisma.messengerConnection.findFirst({
|
||||
where: {
|
||||
id: connectionId,
|
||||
userId: user.id,
|
||||
type: 'TELEGRAM',
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!connection) {
|
||||
res.status(404).json({ error: 'Telegram avatar not found.' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (connection.userId !== user.id) {
|
||||
if (!isManagerRole(user.role)) {
|
||||
res.status(403).json({ error: 'Access denied.' });
|
||||
return;
|
||||
}
|
||||
|
||||
const canAccess = await canManagerAccessUser(prisma, user, connection.userId);
|
||||
if (!canAccess) {
|
||||
res.status(403).json({ error: 'Access denied.' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!connection?.avatarFileId) {
|
||||
res.status(404).json({ error: 'Telegram avatar not found.' });
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user