Mohammed Foud commited on
Commit
480e618
Β·
1 Parent(s): 65edeec

Fix some Bugs and add some Feathers

Browse files
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
- // 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,9 +344,9 @@ export async function handleWeBookEventInfoByUrl(ctx: BotContext) {
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,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 += ` ID: ${tag.id || 'None'}\n`;
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);