MS Teams Bot — создание беседы с пользователем

Я создаю приложение-функцию 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");
  }
}
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Важно помнить, что Bot Framework можно использовать во многих контекстах, Teams — лишь один из них. Таким образом, хотя концепция «создания» разговора существует в Bot Framework, она недействительна в Teams — всегда существует только один «разговор», и вы, по сути, «продолжаете» разговор. Также невозможно первым «инициировать» разговор — это должен сделать пользователь, и это делается путем установки приложения, содержащего бота (которое отправит вашему боту событие установки, на которое он должен ответить сообщением "приветственное сообщение).

В результате то, что вы хотите делать после того, как приложение/бот установлено и вы хотите периодически отправлять сообщения в будущем, называется «Проактивный обмен сообщениями». Вы можете прочитать больше об этом от Microsoft здесь , а также более подробный ответ, который я публиковал ранее, с примером кода и ссылками на видео, по адресу Отправка упреждающих сообщений из внешнего процесса пользователям организации через чат-бот Teams .

Спасибо, Хилтон! Кажется, это ведет меня в правильном направлении. Я ценю это!

Justin J 24.06.2024 20:23

Не за что! Пожалуйста, проголосуйте за ответ или отметьте его как ответ, чтобы другие тоже могли получить пользу, если у них возникнет аналогичный вопрос.

Hilton Giesenow 24.06.2024 20:54

Другие вопросы по теме