Я создаю приложение-функцию Azure, которое должно создавать беседу с каждым пользователем в идентификаторе Entra. Я сталкиваюсь с сообщением об ошибке: Ошибка создания беседы 2: Ошибка: Ошибка создания беседы: Несанкционировано, {"сообщение":"Для этого авторизация отклонена запрос."}. Как создать диалог для каждого пользователя, если бот установлен только в групповом канале. Дайте мне знать, если для этого вопроса потребуется дополнительная информация.
Я использую токен графа, сгенерированный с помощью CCA — код ниже.
const msalConfig = {
auth: {
clientId: process.env.MICROSOFT_APP_ID,
clientSecret: process.env.MICROSOFT_APP_PASSWORD,
authority: `https://login.microsoftonline.com/${process.env.TENANT_ID}`,
}
};
const cca = new ConfidentialClientApplication(msalConfig);
export async function getGraphToken(): Promise<string> {
try {
const authResult = await cca.acquireTokenByClientCredential({
scopes: ['https://graph.microsoft.com/.default']
});
console.info('token', authResult.accessToken)
return authResult.accessToken;
} catch (error) {
console.error("Error acquiring Graph token:", error);
throw new Error("Failed to acquire Graph token");
}
}```
i use this to get every user in Entra and then for each user, i try to create and save a conversation
```import { app, InvocationContext, Timer } from "@azure/functions";
import { saveConversationReference, getAllUsers, CreateConversationForMSTeamsUser, addUserRefToStorage } from "../extra/conversationHandlers";
export async function createConversationInStorage2(myTimer: Timer, context: InvocationContext): Promise<void> {
context.log('Timer function processed request.');
try {
const users = await getAllUsers();
context.log(`Fetched ${users.length} users from Azure AD`);
for (const user of users) {
if (user && user.id) {
context.log(`Processing user: ${user.id}`);
const res = await CreateConversationForMSTeamsUser(user.id, user.displayName, user.userPrincipalName);
if (res) {
await addUserRefToStorage(user.id, res);
} else {
context.log(`Failed to create conversation for user3: ${user.id}`);
}
}
}
} catch (error) {
context.log('Error retrieving users from Azure AD:', error);
}
}
app.timer('createConversationInStorage2', {
schedule: '0 */1 * * * *',
handler: createConversationInStorage2
});```
- handlers below
```import storage from './storageBlob';
import { getBotFrameworkToken, getGraphToken } from './msal';
export async function CreateConversationForMSTeamsUser(userId: string, userDisplayName: string, userPrincipalName: string) {
try {
const tenantId = process.env.TENANT_ID;
// const serviceUrl = 'https://smba.trafficmanager.net/amer/v3/conversations';
const serviceUrl = 'https://smba.trafficmanager.net/teams/v3/conversations'
const token = await getGraphToken();
// console.info('everything', userId, userDisplayName, userPrincipalName, tenantId, serviceUrl)
// console.info('emicrosoft details', 'appid', process.env.MICROSOFT_APP_ID, 'appsecret', process.env.MICROSOFT_APP_PASSWORD, 'tenantid', process.env.TENANT_ID)
const conversationParams = {
members: [
{
id: userId,
displayName: userDisplayName,
userPrincipalName: userPrincipalName
},
],
isGroup: false,
bot: {
id: 'id here',
displayName: 'app name here'
}
};
console.info('conversationParams', conversationParams)
// const conversationParams = {
// activity: 'hi',
// bot: [
// {
// aadObjectId: process.env.MICROSOFT_APP_ID,
// id: 'id here',
// name: 'app name here',
// role: 'bot'
// }
// ],
// channelData: { tenant: { id: tenantId } },
// isGroup: false,
// members: [
// {
// aadObjectId: userId,
// id: `29:${userId}`,
// name: userDisplayName,
// role: 'user',
// userPrincipalName: userPrincipalName
// }
// ],
// tenantId: tenantId,
// topicName: 'General'
// }
const conversationResponse = await fetch(
serviceUrl,
{
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(conversationParams),
}
);
console.info('conversationResponse', conversationResponse)
if (!conversationResponse.ok) {
const errorText = await conversationResponse.text();
throw new Error(`Error creating conversation: ${conversationResponse.statusText}, ${errorText}`);
}
const conversation = await conversationResponse.json();
console.info('conversation', conversation)
return conversation;
} catch (error) {
console.error('Error creating conversation2:', error);
return null;
}
}
export async function saveConversationReference(userId: string, conversationId: string) {
const reference = {
user: { id: userId },
conversation: { id: conversationId }
};
try {
const res = await storage.add(userId, reference, { overwrite: true });
console.info(`Conversation reference saved for user ${userId}:`, res);
} catch (error) {
console.error(`Error saving conversation reference for user ${userId}:`, error);
}
}
export async function getAllUsers(): Promise<any[]> {
const token = await getGraphToken();
const usersResponse = await fetch("https://graph.microsoft.com/v1.0/users", {
headers: {
Authorization: `Bearer ${token}`
},
});
if (!usersResponse.ok) {
throw new Error(`Error fetching users: ${usersResponse.statusText}`);
}
const usersJson = await usersResponse.json();
if (!usersJson.value || !Array.isArray(usersJson.value)) {
throw new TypeError('Expected an array of users in the response');
}
return usersJson.value;
}
export async function addUserRefToStorage(userId: string, conversationRef: any) {
try {
if (!conversationRef) {
throw new Error('Invalid conversation reference');
}
const res = await storage.add(userId, conversationRef, { overwrite: true });
console.info(`User ID saved for user ${userId}:`, res);
} catch (error) {
console.error(`Error saving user conversation reference for ${userId}:`, error);
}
}
try {
const authResult = await cca.acquireTokenByClientCredential({
scopes: ['https://api.botframework.com/.default']
// scopes: ['https://smba.trafficmanager.net/.default']
});
console.info('authResult', authResult.accessToken);
return authResult.accessToken;
} catch (error) {
console.error("Error acquiring Bot Framework token:", error);
throw new Error("Failed to acquire Bot Framework token");
}
}
Важно помнить, что Bot Framework можно использовать во многих контекстах, Teams — лишь один из них. Таким образом, хотя концепция «создания» разговора существует в Bot Framework, она недействительна в Teams — всегда существует только один «разговор», и вы, по сути, «продолжаете» разговор. Также невозможно первым «инициировать» разговор — это должен сделать пользователь, и это делается путем установки приложения, содержащего бота (которое отправит вашему боту событие установки, на которое он должен ответить сообщением "приветственное сообщение).
В результате то, что вы хотите делать после того, как приложение/бот установлено и вы хотите периодически отправлять сообщения в будущем, называется «Проактивный обмен сообщениями». Вы можете прочитать больше об этом от Microsoft здесь , а также более подробный ответ, который я публиковал ранее, с примером кода и ссылками на видео, по адресу Отправка упреждающих сообщений из внешнего процесса пользователям организации через чат-бот Teams .
Не за что! Пожалуйста, проголосуйте за ответ или отметьте его как ответ, чтобы другие тоже могли получить пользу, если у них возникнет аналогичный вопрос.
Спасибо, Хилтон! Кажется, это ведет меня в правильном направлении. Я ценю это!