Neet help in a Telegram pack code

It work fine now,

Many thanks @Eric_Koleda

Any plan on adding preview for videos and pdfs file types for coda packs ? (embeding ?)

1 Like

If you upload a video with the correct content type they it should show in a media player when clicked (after the virus scan has completed). We currently don’t support directly embedding media uploaded this way, as far as I know.

hi @Omar_Mhammedi , would you share your telegram pack with the community? :slight_smile:

Thanks! :slight_smile:

1 Like

Hi Mario,
I have put the creation of the pack on hold until i learn more javascript.
it work but not as i want it to, i think the last edits i made in the code was an attempt to show a full message in the same column (with all the “reply to” forward to" embeded thumbs… )

i strugled with the dynamic sync table, i still didn’t manage to show the chat names from a list in the pack setting.

It would be nice if we can all contribute something on it and make it public pack code for coda.

PS : Sorry in advance if something is wrong with the code, i don’t remember what’s the last thing i tried. Also you 80% of this code is with the help of ChatGPT … i’m sure it will hurt the fellings of developpers :stuck_out_tongue:

Here is the last code :

import * as coda from "@codahq/packs-sdk";
export const pack = coda.newPack();

pack.setSystemAuthentication({
  type: coda.AuthenticationType.Custom,
  params: [
    { name: "bot_api_key", description: "The API key" },
  ],
});

pack.addNetworkDomain("api.telegram.org");

const TaskSchema = coda.makeObjectSchema({
  properties: {
    message: {
      description: "Message.",
      type: coda.ValueType.String,
      codaType: coda.ValueHintType.Html,
    },
    from: {
      description: "Message sender.",
      type: coda.ValueType.String,
    },
    date: {
      description: "Date in Unix format.",
      type: coda.ValueType.Number,
      codaType: coda.ValueHintType.DateTime,
    },
    message_id: {
      description: "The ID of the message.",
      type: coda.ValueType.Number,
    },
    download: {
      description: "files.",
      type: coda.ValueType.String,
      codaType: coda.ValueHintType.ImageAttachment,
    },
    group: {
      description: "The ID of the task.",
      type: coda.ValueType.String,
    },
    chatID: {
      description: "The ID of the chat.",
      type: coda.ValueType.Number,
    },
  },
  displayProperty: "message",
  idProperty: "message_id",
  featuredProperties: ["Message", "from", "date",],
});


async function getFilePath(file_id, context, update) {
  let allowedSize = 4194304;
  let invocationToken = context.invocationToken;
  let keyPlaceholder = "{{bot_api_key-" + invocationToken + "}}";
  let response = await context.fetcher.fetch({
    method: "GET",
    url: "https://api.telegram.org/bot" + keyPlaceholder + "/getFile?file_id=" + file_id,
  });
  let size = response.body.result.file_size;
  if (size > allowedSize) return;

  let filePath = response.body.result.file_path;
  let fileName;
  if (update.message.document) fileName = update.message.document.file_name;
  else if (update.message.video) fileName = update.message.video.file_name;
  else fileName = 'file.jpg'
  let privateImageUrl = "https://api.telegram.org/file/bot" + keyPlaceholder + "/" + filePath;
  let temporaryImageUrl = await context.temporaryBlobStorage.storeUrl(privateImageUrl, {
    downloadFilename: fileName,
  });
  return temporaryImageUrl;
}

async function formatItems(update, username, chatTitle, context) {
  {
    if (!update.message) {
      return;
    }
    if (username) {
      if (!update.message.entities) {
        return;
      }
      let entities = update.message.entities;
      let isMention = entities.some(function (entity) {
        return entity.type === "mention" && update.message.text.substring(entity.offset, entity.offset + entity.length) === username;
      });
      if (!isMention) {
        return;
      }
    }
    if (chatTitle && update.message.chat.title !== chatTitle) {
      return;
    }
    let message, download, preview, videoFilename, documentFilename,
      forwardFrom = update.message?.forward_from?.username ? 
  `<u><strong>forwarded from:</strong></u> <u>${update.message.forward_from.username}</u><br>` : "",
      replyTo = update.message?.reply_to_message ? `<b><u>reply to:_</u></b> ${(update.message.reply_to_message.text && `<u><i>${update.message.reply_to_message.text}</i></u><br>`) 
  || `<img width="100px"src="${await getFilePath((update.message.reply_to_message.photo && update.message.reply_to_message.photo[update.message.reply_to_message.photo.length - 1].file_id) || update.message.reply_to_message.document?.thumb?.file_id || update.message.reply_to_message.video?.thumb?.file_id, context, update) }" alt="Image"><br>`}` : "";

    if (update.message && update.message.photo) {
      let lastIndex = update.message.photo.length - 1;
      download = await getFilePath(update.message.photo[lastIndex].file_id, context, update);
      let previewHtml = `<img src="${download}" alt="Image">`;
      message = `${forwardFrom}${replyTo}${previewHtml}\n${update.message.caption || ''}`;

    } else if (update.message && update.message.video) {
      if (!update.message.video.file_id) return;
      preview = await getFilePath(update.message.video.thumb.file_id, context, update);
      download = await getFilePath(update.message.video.file_id, context, update);
      videoFilename = update.message.video.file_name;
      let previewHtmlThumb = `<img src="${preview}" alt="Image">`;
      let downloadHtml = `<a href="${download}">${videoFilename}</a>`;
      message = `${forwardFrom}${replyTo}${previewHtmlThumb}\n${update.message.caption || ''}\n${downloadHtml}`;

    } else if (update.message && update.message.document) {
      if (!update.message.document.file_id) return;
      preview = await getFilePath(update.message.document.thumb.file_id, context, update);
      download = await getFilePath(update.message.document.file_id, context, update);
      documentFilename = update.message.document.file_name;
      let previewHtmlThumb = `<img src="${preview}" alt="Image">`;
      let downloadHtml = `<a href="${download}">${documentFilename}</a>`;
      message = `${forwardFrom}${replyTo}${previewHtmlThumb}\n${update.message.caption || ''}\n${downloadHtml}`;

    } else if (update.message && update.message.text) {
      message = `${forwardFrom}${replyTo}${update.message.text}`;
    }

    if (update.message) {
      return {
        message: message,
        from: update.message.from ? update.message.from.first_name : '',
        date: update.message.date ? update.message.date : '',
        group: update.message.chat.title ? update.message.chat.title : '',
        chatID: update.message.chat.id ? update.message.chat.id : '',
        message_id: update.message.message_id ? update.message.message_id : '',
      };
    }
  }
}

pack.addSyncTable({
  name: "Messages",
  schema: TaskSchema,
  identityName: "MessageTable",
  formula: {
    name: "SyncMessages",
    description: "Sync from telegram",
    parameters: [
      coda.makeParameter({
        type: coda.ParameterType.String,
        name: "chatTitle",
        description: "The Title of the chat to retrieve messages from",
        optional: true,
      }),
      coda.makeParameter({
        type: coda.ParameterType.String,
        name: "username",
        description: "The username to filter messages by",
        optional: true,
      }),
    ],
    execute: async function ([chatTitle = "", username = ""], context) {
      let invocationToken = context.invocationToken;
      let keyPlaceholder = "{{bot_api_key-" + invocationToken + "}}";
      let url = "https://api.telegram.org/bot" + keyPlaceholder + "/getUpdates";
      let response = await context.fetcher.fetch({
        method: "GET",
        url: url,
      });
      let results = response.body.result;
      let items = [];
      for (let result of results) {
        let formattedItem = await formatItems(result, username, chatTitle, context);
        if (formattedItem) {
          items.push(formattedItem);
        }
      }
      return {
        result: items,
      };
    },
  },
});

pack.addFormula({
  name: "Chats",
  description: "list telegram API group chat Id's",
  parameters: [],
  resultType: coda.ValueType.Array,
  items: {
    type: coda.ValueType.Object,
    properties: {
      title: { type: coda.ValueType.String },
      id: { type: coda.ValueType.Number },
    },
  },
  execute: async function ([], context) {
    let invocationToken = context.invocationToken;
    let keyPlaceholder = "{{bot_api_key-" + invocationToken + "}}";
    let url = "https://api.telegram.org/bot" + keyPlaceholder + "/getUpdates";
    let response = await context.fetcher.fetch({
      method: "GET",
      url: url,
    });
    // Create a Set to store seen ids
    const seenIds = new Set();
    // Filter the result array to only include group chats and unique ids
    return response.body.result
      .filter((update) => update.message && update.message.chat && (update.message.chat.type === "supergroup" || update.message.chat.type === "group"))
      .filter((update) => {
        if (!seenIds.has(update.message.chat.id)) {
          seenIds.add(update.message.chat.id);
          return true;
        }
        return false;
      })
      .map((update) => {
        return {
          title: update.message.chat.title,
          id: update.message.chat.id,
        };
      });
  },
});

pack.addFormula({
  name: "SendMessage",
  description: "Send a reply to a message in a specified chat",
  parameters: [
    coda.makeParameter({
      type: coda.ParameterType.String,
      name: "text",
      description: "Message body.",
    }),
    coda.makeParameter({
      type: coda.ParameterType.Number,
      name: "chatId",
      description: "Unique identifier for the target group chat.",
    }),
  ],
  resultType: coda.ValueType.Boolean,
  isAction: true,
  execute: async function ([text, chatId], context) {
    let invocationToken = context.invocationToken;
    let keyPlaceholder = "{{bot_api_key-" + invocationToken + "}}";
    let url = `https://api.telegram.org/bot${keyPlaceholder}/sendMessage?chat_id=${chatId}&text=${text}`;
    let response = await context.fetcher.fetch({
      method: "POST",
      url: url,
      headers: {
        "Content-Type": "application/json",
      },
    });
    return response.body.ok;
  },
});

1 Like

@Omar_Mhammedi OMAR WHAT YOU SAID IT’S MIND BLOWING!


Should we make a petition for asking coda to evaluate an integration of this possibilities? :heart_eyes: :heart_eyes: :heart_eyes:

P.s. sadly my competence in the coding field is so limited that i can barely understand what your code does, i cannot immagine being a contributor of it :frowning:

1 Like

@Mario and @Omar_Mhammedi I just released a first version of a Telegram Bot Pack, it includes an Updates sync table and a SendMessage action.

Will be adding additional features in the future :slight_smile:

2 Likes

Amazing, thank you. would be great if we could reply to a message :stuck_out_tongue:

1 Like

On the roadmap, will tackle new week and add additional parameters :wink:

You can now reply to a message and I’ve added some additional options as well.

1 Like