Spaces:
Paused
Paused
Mohammed Foud
commited on
Commit
Β·
480e618
1
Parent(s):
65edeec
Fix some Bugs and add some Feathers
Browse files- src/bots/handlers/webookHandlers.ts +88 -12
- src/webook/webookApi.ts +60 -0
- test_rest_api.js +88 -0
src/bots/handlers/webookHandlers.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { BotContext } from "../types/botTypes";
|
|
| 2 |
import { createLogger } from '../../utils/logger';
|
| 3 |
import { callbackReplyHandler } from "../utils/handlerUtils";
|
| 4 |
import { messageManager } from "../utils/messageManager";
|
| 5 |
-
import { webookAPI, EventFilters, getEventDetailsByUrl } from '../../webook/webookApi';
|
| 6 |
import { Markup } from "telegraf";
|
| 7 |
import { getBackToMainMenuButton, getLoggedInMenuKeyboard } from "../utils/keyboardUtils";
|
| 8 |
import {
|
|
@@ -325,14 +325,14 @@ export async function handleWeBookEventInfoByUrl(ctx: BotContext) {
|
|
| 325 |
// }
|
| 326 |
|
| 327 |
// // Schedule
|
| 328 |
-
|
| 329 |
-
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
|
| 333 |
-
|
| 334 |
-
|
| 335 |
-
|
| 336 |
|
| 337 |
// // Season
|
| 338 |
// if (event.season) {
|
|
@@ -344,9 +344,9 @@ export async function handleWeBookEventInfoByUrl(ctx: BotContext) {
|
|
| 344 |
// // Category
|
| 345 |
if (event.category) {
|
| 346 |
info += `<b>Category:</b>\n`;
|
| 347 |
-
|
| 348 |
info += `- Title: ${event.category.title || 'None'}\n`;
|
| 349 |
-
|
| 350 |
}
|
| 351 |
|
| 352 |
|
|
@@ -386,7 +386,7 @@ export async function handleWeBookEventInfoByUrl(ctx: BotContext) {
|
|
| 386 |
// for (const tag of event.cmsTagsCollection.items) {
|
| 387 |
// info += `- Title: ${tag.title || 'None'}\n`;
|
| 388 |
// info += ` Slug: ${tag.slug || 'None'}\n`;
|
| 389 |
-
// info += `
|
| 390 |
// if (tag.background) {
|
| 391 |
// info += ` Background: ${tag.background.url || 'None'} (${tag.background.title || ''})\n`;
|
| 392 |
// }
|
|
@@ -403,6 +403,82 @@ export async function handleWeBookEventInfoByUrl(ctx: BotContext) {
|
|
| 403 |
} else {
|
| 404 |
await ctx.reply(info, { parse_mode: 'HTML' });
|
| 405 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 406 |
await ctx.deleteMessage(loadingMsg.message_id);
|
| 407 |
return event;
|
| 408 |
}
|
|
|
|
| 2 |
import { createLogger } from '../../utils/logger';
|
| 3 |
import { callbackReplyHandler } from "../utils/handlerUtils";
|
| 4 |
import { messageManager } from "../utils/messageManager";
|
| 5 |
+
import { webookAPI, EventFilters, getEventDetailsByUrl, getEventDetailsBySlug, getEventDetailsByUrlRest } from '../../webook/webookApi';
|
| 6 |
import { Markup } from "telegraf";
|
| 7 |
import { getBackToMainMenuButton, getLoggedInMenuKeyboard } from "../utils/keyboardUtils";
|
| 8 |
import {
|
|
|
|
| 325 |
// }
|
| 326 |
|
| 327 |
// // Schedule
|
| 328 |
+
if (event.schedule) {
|
| 329 |
+
info += `<b>Schedule:</b>\n`;
|
| 330 |
+
info += `- Title: ${event.schedule.title || 'None'}\n`;
|
| 331 |
+
info += `- Open Title: ${event.schedule.openTitle || 'None'}\n`;
|
| 332 |
+
info += `- Open DateTime: ${event.schedule.openDateTime || 'None'}\n`;
|
| 333 |
+
info += `- Close DateTime: ${event.schedule.closeDateTime || 'None'}\n`;
|
| 334 |
+
info += `- Open Schedule Text: ${event.schedule.openScheduleText || 'None'}\n`;
|
| 335 |
+
}
|
| 336 |
|
| 337 |
// // Season
|
| 338 |
// if (event.season) {
|
|
|
|
| 344 |
// // Category
|
| 345 |
if (event.category) {
|
| 346 |
info += `<b>Category:</b>\n`;
|
| 347 |
+
info += `- ID: ${event.category.id || 'None'}\n`;
|
| 348 |
info += `- Title: ${event.category.title || 'None'}\n`;
|
| 349 |
+
info += `- Slug: ${event.category.slug || 'None'}\n`;
|
| 350 |
}
|
| 351 |
|
| 352 |
|
|
|
|
| 386 |
// for (const tag of event.cmsTagsCollection.items) {
|
| 387 |
// info += `- Title: ${tag.title || 'None'}\n`;
|
| 388 |
// info += ` Slug: ${tag.slug || 'None'}\n`;
|
| 389 |
+
// info += ` Slug: ${tag.id || 'None'}\n`;
|
| 390 |
// if (tag.background) {
|
| 391 |
// info += ` Background: ${tag.background.url || 'None'} (${tag.background.title || ''})\n`;
|
| 392 |
// }
|
|
|
|
| 403 |
} else {
|
| 404 |
await ctx.reply(info, { parse_mode: 'HTML' });
|
| 405 |
}
|
| 406 |
+
await ctx.deleteMessage(loadingMsg.message_id);
|
| 407 |
+
return event;
|
| 408 |
+
}
|
| 409 |
+
|
| 410 |
+
/**
|
| 411 |
+
* Handler to reply with event info using REST API when user sends a WeBook event URL
|
| 412 |
+
*/
|
| 413 |
+
export async function handleWeBookEventInfoByUrlRest(ctx: BotContext) {
|
| 414 |
+
const message = ctx.message;
|
| 415 |
+
if (!message || typeof message !== 'object' || !('text' in message) || typeof message.text !== 'string') return null;
|
| 416 |
+
const url = message.text.trim();
|
| 417 |
+
if (!isValidWeBookEventUrl(url)) return null;
|
| 418 |
+
|
| 419 |
+
const loadingMsg = await ctx.reply('Fetching event information from REST API...');
|
| 420 |
+
const event = await getEventDetailsByUrlRest(url);
|
| 421 |
+
|
| 422 |
+
if (!event) {
|
| 423 |
+
await ctx.deleteMessage(loadingMsg.message_id);
|
| 424 |
+
await ctx.reply('Could not find event information for this URL.');
|
| 425 |
+
return null;
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
// Format event info from REST API response
|
| 429 |
+
let info = `<b>Event Information (REST API)</b>\n`;
|
| 430 |
+
info += `<b>Title:</b> ${event.title || 'None'}\n`;
|
| 431 |
+
info += `<b>ID:</b> ${event._id || 'None'}\n`;
|
| 432 |
+
info += `<b>Slug:</b> ${event.slug || 'None'}\n`;
|
| 433 |
+
info += `<b>Description:</b> ${event.description ? event.description.replace(/<[^>]*>/g, '').substring(0, 200) + '...' : 'None'}\n`;
|
| 434 |
+
info += `<b>Starting Price:</b> ${event.event_start_price || 'None'} ${event.currency || ''}\n`;
|
| 435 |
+
info += `<b>VAT:</b> ${event.event_start_price_vat || 'None'} ${event.currency || ''}\n`;
|
| 436 |
+
|
| 437 |
+
// Location information
|
| 438 |
+
if (event.location) {
|
| 439 |
+
info += `<b>Location:</b>\n`;
|
| 440 |
+
info += `- Address: ${event.address || 'None'}\n`;
|
| 441 |
+
info += `- City: ${event.city || 'None'}\n`;
|
| 442 |
+
info += `- Venue: ${event.venue_name || 'None'}\n`;
|
| 443 |
+
if (event.location.lat && event.location.lng) {
|
| 444 |
+
info += `- Coordinates: ${event.location.lat}, ${event.location.lng}\n`;
|
| 445 |
+
}
|
| 446 |
+
}
|
| 447 |
+
|
| 448 |
+
// Organization information
|
| 449 |
+
if (event.organization) {
|
| 450 |
+
info += `<b>Organization:</b>\n`;
|
| 451 |
+
info += `- Name: ${event.organization.name || 'None'}\n`;
|
| 452 |
+
info += `- Slug: ${event.organization.slug || 'None'}\n`;
|
| 453 |
+
info += `- Status: ${event.organization.status || 'None'}\n`;
|
| 454 |
+
}
|
| 455 |
+
|
| 456 |
+
// Ticket information
|
| 457 |
+
if (event.event_tickets && Array.isArray(event.event_tickets)) {
|
| 458 |
+
info += `<b>Tickets Available:</b>\n`;
|
| 459 |
+
event.event_tickets.forEach((ticket: any, index: number) => {
|
| 460 |
+
info += `${index + 1}. ${ticket.title || 'Unknown'}\n`;
|
| 461 |
+
info += ` Price: ${ticket.price || 'None'} ${ticket.currency || ''}\n`;
|
| 462 |
+
info += ` Remaining: ${ticket.remaining || 'None'}\n`;
|
| 463 |
+
info += ` Sold Out: ${ticket.sold_out ? 'Yes' : 'No'}\n`;
|
| 464 |
+
});
|
| 465 |
+
}
|
| 466 |
+
|
| 467 |
+
// Additional event details
|
| 468 |
+
info += `<b>Is Sold Out:</b> ${event.is_soldout ? 'Yes' : 'No'}\n`;
|
| 469 |
+
info += `<b>Require Visa:</b> ${event.require_visa ? 'Yes' : 'No'}\n`;
|
| 470 |
+
info += `<b>VAT Percent:</b> ${event.vat_percent || 'None'}%\n`;
|
| 471 |
+
info += `<b>Event Order Limit:</b> ${event.event_order_limit || 'None'}\n`;
|
| 472 |
+
|
| 473 |
+
// Send image if available, else send info as text
|
| 474 |
+
if (event.poster) {
|
| 475 |
+
await ctx.replyWithPhoto({ url: event.poster }, { caption: info, parse_mode: 'HTML' });
|
| 476 |
+
} else if (event.mobile_poster) {
|
| 477 |
+
await ctx.replyWithPhoto({ url: event.mobile_poster }, { caption: info, parse_mode: 'HTML' });
|
| 478 |
+
} else {
|
| 479 |
+
await ctx.reply(info, { parse_mode: 'HTML' });
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
await ctx.deleteMessage(loadingMsg.message_id);
|
| 483 |
return event;
|
| 484 |
}
|
src/webook/webookApi.ts
CHANGED
|
@@ -395,4 +395,64 @@ export async function getEventDetailsByUrl(eventUrl: string): Promise<any | null
|
|
| 395 |
console.error('Error fetching event details:', e);
|
| 396 |
return null;
|
| 397 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 398 |
}
|
|
|
|
| 395 |
console.error('Error fetching event details:', e);
|
| 396 |
return null;
|
| 397 |
}
|
| 398 |
+
}
|
| 399 |
+
|
| 400 |
+
/**
|
| 401 |
+
* Fetch event details from WeBook REST API by event slug
|
| 402 |
+
* @param slug string - event slug (e.g. al-awwal-tour-stadium-tickets-843728)
|
| 403 |
+
* @param lang string - language code (default: 'en')
|
| 404 |
+
* @param visibleIn string - visibility filter (default: 'rs')
|
| 405 |
+
* @returns event details object or null
|
| 406 |
+
*/
|
| 407 |
+
export async function getEventDetailsBySlug(
|
| 408 |
+
slug: string,
|
| 409 |
+
lang: string = 'en',
|
| 410 |
+
visibleIn: string = 'rs'
|
| 411 |
+
): Promise<any | null> {
|
| 412 |
+
try {
|
| 413 |
+
const url = `https://api.webook.com/api/v2/event-detail/${slug}?lang=${lang}&visible_in=${visibleIn}`;
|
| 414 |
+
|
| 415 |
+
const response = await axios.get(url, {
|
| 416 |
+
headers: {
|
| 417 |
+
"Accept": "*/*",
|
| 418 |
+
"Accept-Encoding": "gzip, deflate, br, zstd",
|
| 419 |
+
"Accept-Language": "en-US,en;q=0.9,ar;q=0.8",
|
| 420 |
+
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
| 421 |
+
}
|
| 422 |
+
});
|
| 423 |
+
|
| 424 |
+
if (response.data && response.data.status === 'success' && response.data.data) {
|
| 425 |
+
return response.data.data;
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
return null;
|
| 429 |
+
} catch (error) {
|
| 430 |
+
console.error('Error fetching event details by slug:', error);
|
| 431 |
+
return null;
|
| 432 |
+
}
|
| 433 |
+
}
|
| 434 |
+
|
| 435 |
+
/**
|
| 436 |
+
* Extract slug from WeBook event URL and fetch details using REST API
|
| 437 |
+
* @param eventUrl string - full event URL (e.g. https://webook.com/en/events/slug)
|
| 438 |
+
* @param lang string - language code (default: 'en')
|
| 439 |
+
* @param visibleIn string - visibility filter (default: 'rs')
|
| 440 |
+
* @returns event details object or null
|
| 441 |
+
*/
|
| 442 |
+
export async function getEventDetailsByUrlRest(
|
| 443 |
+
eventUrl: string,
|
| 444 |
+
lang: string = 'en',
|
| 445 |
+
visibleIn: string = 'rs'
|
| 446 |
+
): Promise<any | null> {
|
| 447 |
+
try {
|
| 448 |
+
// Extract slug from URL
|
| 449 |
+
const match = eventUrl.match(/\/events\/([a-zA-Z0-9\-]+)/);
|
| 450 |
+
if (!match || !match[1]) return null;
|
| 451 |
+
const slug = match[1];
|
| 452 |
+
|
| 453 |
+
return await getEventDetailsBySlug(slug, lang, visibleIn);
|
| 454 |
+
} catch (error) {
|
| 455 |
+
console.error('Error extracting slug from URL:', error);
|
| 456 |
+
return null;
|
| 457 |
+
}
|
| 458 |
}
|
test_rest_api.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const axios = require('axios');
|
| 2 |
+
|
| 3 |
+
/**
|
| 4 |
+
* Test function to get event details using the REST API
|
| 5 |
+
* @param slug string - event slug (e.g. al-awwal-tour-stadium-tickets-843728)
|
| 6 |
+
* @param lang string - language code (default: 'en')
|
| 7 |
+
* @param visibleIn string - visibility filter (default: 'rs')
|
| 8 |
+
*/
|
| 9 |
+
async function getEventDetailsBySlug(slug, lang = 'en', visibleIn = 'rs') {
|
| 10 |
+
try {
|
| 11 |
+
const url = `https://api.webook.com/api/v2/event-detail/${slug}?lang=${lang}&visible_in=${visibleIn}`;
|
| 12 |
+
|
| 13 |
+
console.log(`Fetching event details from: ${url}`);
|
| 14 |
+
|
| 15 |
+
const response = await axios.get(url, {
|
| 16 |
+
headers: {
|
| 17 |
+
"Accept": "*/*",
|
| 18 |
+
"Accept-Encoding": "gzip, deflate, br, zstd",
|
| 19 |
+
"Accept-Language": "en-US,en;q=0.9,ar;q=0.8",
|
| 20 |
+
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
|
| 21 |
+
}
|
| 22 |
+
});
|
| 23 |
+
|
| 24 |
+
if (response.data && response.data.status === 'success' && response.data.data) {
|
| 25 |
+
console.log('β
Success! Event details:');
|
| 26 |
+
console.log(JSON.stringify(response.data.data, null, 2));
|
| 27 |
+
return response.data.data;
|
| 28 |
+
} else {
|
| 29 |
+
console.log('β No data found or invalid response');
|
| 30 |
+
console.log('Response:', response.data);
|
| 31 |
+
return null;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
} catch (error) {
|
| 35 |
+
console.error('β Error fetching event details:', error.message);
|
| 36 |
+
if (error.response) {
|
| 37 |
+
console.error('Response status:', error.response.status);
|
| 38 |
+
console.error('Response data:', error.response.data);
|
| 39 |
+
}
|
| 40 |
+
return null;
|
| 41 |
+
}
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
/**
|
| 45 |
+
* Extract slug from WeBook event URL and fetch details
|
| 46 |
+
* @param eventUrl string - full event URL
|
| 47 |
+
*/
|
| 48 |
+
async function getEventDetailsByUrl(eventUrl) {
|
| 49 |
+
try {
|
| 50 |
+
// Extract slug from URL
|
| 51 |
+
const match = eventUrl.match(/\/events\/([a-zA-Z0-9\-]+)/);
|
| 52 |
+
if (!match || !match[1]) {
|
| 53 |
+
console.log('β Could not extract slug from URL:', eventUrl);
|
| 54 |
+
return null;
|
| 55 |
+
}
|
| 56 |
+
const slug = match[1];
|
| 57 |
+
console.log(`Extracted slug: ${slug}`);
|
| 58 |
+
|
| 59 |
+
return await getEventDetailsBySlug(slug);
|
| 60 |
+
} catch (error) {
|
| 61 |
+
console.error('β Error extracting slug from URL:', error);
|
| 62 |
+
return null;
|
| 63 |
+
}
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
// Test the function with the provided example
|
| 67 |
+
async function test() {
|
| 68 |
+
console.log('π§ͺ Testing WeBook REST API...\n');
|
| 69 |
+
|
| 70 |
+
// Test 1: Direct slug
|
| 71 |
+
console.log('π Test 1: Direct slug');
|
| 72 |
+
await getEventDetailsBySlug('al-awwal-tour-stadium-tickets-843728');
|
| 73 |
+
|
| 74 |
+
console.log('\n' + '='.repeat(50) + '\n');
|
| 75 |
+
|
| 76 |
+
// Test 2: From URL
|
| 77 |
+
console.log('π Test 2: From URL');
|
| 78 |
+
await getEventDetailsByUrl('https://webook.com/en/events/al-awwal-tour-stadium-tickets-843728');
|
| 79 |
+
|
| 80 |
+
console.log('\n' + '='.repeat(50) + '\n');
|
| 81 |
+
|
| 82 |
+
// Test 3: Different language
|
| 83 |
+
console.log('π Test 3: Arabic language');
|
| 84 |
+
await getEventDetailsBySlug('al-awwal-tour-stadium-tickets-843728', 'ar', 'rs');
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
// Run the test
|
| 88 |
+
test().catch(console.error);
|