UNPKG

@warriorteam/redai-zalo-sdk

Version:

Comprehensive TypeScript/JavaScript SDK for Zalo APIs - Official Account, ZNS, Consultation Service, Group Messaging, and Social APIs

564 lines 22.4 kB
"use strict"; /** * User management service for Zalo API * Handles all user-related operations with specific endpoints */ Object.defineProperty(exports, "__esModule", { value: true }); exports.UserService = void 0; const common_1 = require("../types/common"); /** * User management service for handling user operations * Each method uses specific Zalo API endpoints */ class UserService { constructor(client) { this.client = client; // Zalo API endpoints - organized by functionality this.endpoints = { // User management endpoints user: { getList: "https://openapi.zalo.me/v3.0/oa/user/getlist", postList: "https://openapi.zalo.me/v3.0/oa/user/getlist", getDetail: "https://openapi.zalo.me/v3.0/oa/user/detail", update: "https://openapi.zalo.me/v3.0/oa/user/update", delete: "https://openapi.zalo.me/v2.0/oa/deletefollowerinfo", getCustomInfo: "https://openapi.zalo.me/v3.0/oa/user/detail/custominfo", updateCustomInfo: "https://openapi.zalo.me/v3.0/oa/user/update/custominfo", }, // Tag management endpoints tag: { addToUser: "https://openapi.zalo.me/v2.0/oa/tag/tagfollower", removeFromUser: "https://openapi.zalo.me/v2.0/oa/tag/rmfollowerfromtag", getList: "https://openapi.zalo.me/v2.0/oa/tag/gettagsofoa", delete: "https://openapi.zalo.me/v2.0/oa/tag/rmtag", }, }; } /** * Truy xuất chi tiết người dùng * Endpoint: https://openapi.zalo.me/v3.0/oa/user/detail * Method: GET with data parameter as JSON string * * @param accessToken OA access token * @param userId User ID to get details for * @returns Promise<UserInfo> - Detailed user information */ async getUserInfo(accessToken, userId) { try { // Build data object according to API spec const dataObject = { user_id: userId }; // Send data as JSON string parameter according to API spec const params = { data: JSON.stringify(dataObject), }; const result = await this.client.apiGet(this.endpoints.user.getDetail, accessToken, params); if (result.error !== 0) { throw new common_1.ZaloSDKError(result.message || "Failed to get user information", result.error, result); } if (!result.data) { throw new common_1.ZaloSDKError("No user data received", -1); } return result.data; } catch (error) { if (error instanceof common_1.ZaloSDKError) { throw error; } this.handleError(error, "Failed to get user info"); } } /** * Truy xuất danh sách người dùng * Endpoint: https://openapi.zalo.me/v3.0/oa/user/getlist * Method: GET with data parameter as JSON string * * @param accessToken OA access token * @param request User list request parameters * @returns Promise<UserListResponse> - List of users with pagination info */ async getUserList(accessToken, request) { try { // Build data object according to API spec const dataObject = { offset: request.offset, count: Math.min(request.count, 50), // Max 50 users per request ...(request.tag_name && { tag_name: request.tag_name }), ...(request.last_interaction_period && { last_interaction_period: request.last_interaction_period, }), ...(request.is_follower !== undefined && { is_follower: request.is_follower, }), }; // Send data as JSON string parameter according to API spec const params = { data: encodeURIComponent(JSON.stringify(dataObject)), }; const result = await this.client.apiGet(this.endpoints.user.getList, accessToken, params); if (result.error !== 0) { throw new common_1.ZaloSDKError(result.message || "Failed to get user list", result.error, result); } if (!result.data) { throw new common_1.ZaloSDKError("No user list data received", -1); } return result.data; } catch (error) { if (error instanceof common_1.ZaloSDKError) { throw error; } this.handleError(error, "Failed to get user list"); } } /** * Truy xuất danh sách người dùng (POST method) * Endpoint: https://openapi.zalo.me/v3.0/oa/user/getlist * Method: POST with data in request body * * @param accessToken OA access token * @param request User list request parameters * @returns Promise<UserListResponse> - List of users with pagination info */ async postUserList(accessToken, request) { try { // Build data object according to API spec const dataObject = { offset: request.offset, count: Math.min(request.count, 50), // Max 50 users per request ...(request.tag_name && { tag_name: request.tag_name }), ...(request.last_interaction_period && { last_interaction_period: request.last_interaction_period, }), ...(request.is_follower !== undefined && { is_follower: request.is_follower, }), }; const result = await this.client.apiPost(this.endpoints.user.postList, accessToken, dataObject); if (result.error !== 0) { throw new common_1.ZaloSDKError(result.message || "Failed to get user list", result.error, result); } if (!result.data) { throw new common_1.ZaloSDKError("No user list data received", -1); } return result.data; } catch (error) { if (error instanceof common_1.ZaloSDKError) { throw error; } this.handleError(error, "Failed to get user list"); } } /** * Get all users with automatic pagination * Lấy tất cả users với phân trang tự động, đảm bảo lấy 100% * * @param accessToken Access token của OA * @param filters Bộ lọc tùy chọn * @returns Promise<UserInfo[]> - Danh sách đầy đủ tất cả users */ async getAllUsers(accessToken, filters) { const users = []; let offset = 0; const count = 50; // Max per request let totalUsers = 0; let fetchedUsers = 0; try { while (true) { const userListResponse = await this.getUserList(accessToken, { offset, count, ...filters, }); // Lần đầu tiên, lưu tổng số users if (offset === 0) { totalUsers = userListResponse.total; console.log(`Total users to fetch: ${totalUsers}`); // Cảnh báo nếu vượt quá giới hạn Zalo API if (totalUsers > 10000) { console.warn(`Warning: Total users (${totalUsers}) exceeds Zalo API limit (10000). ` + `Only first 10000 users can be fetched due to max offset = 9951.`); } } // Get detailed info for each user const userIds = userListResponse.users.map((u) => u.user_id); const userInfoPromises = userIds.map((userId) => this.getUserInfo(accessToken, userId)); const userInfos = await Promise.all(userInfoPromises); users.push(...userInfos); fetchedUsers += userInfos.length; console.log(`Fetched ${fetchedUsers}/${totalUsers} users`); // Điều kiện dừng ĐÚNG: // 1. Không còn users trong response // 2. Hoặc đã lấy đủ số lượng theo total // 3. Hoặc số users trả về ít hơn count (page cuối) if (userListResponse.users.length === 0 || fetchedUsers >= totalUsers || userListResponse.users.length < count) { break; } offset += count; // Protection: Tránh infinite loop // Zalo giới hạn max offset = 9951 (tương ứng 10000 người dùng) if (offset > 9951) { console.warn("Reached Zalo maximum offset limit (9951), stopping pagination"); break; } } console.log(`Successfully fetched all ${users.length} users`); return users; } catch (error) { if (error instanceof common_1.ZaloSDKError) { throw error; } this.handleError(error, "Failed to get all users"); } } /** * Get all user IDs only (without detailed info) - Faster version * Chỉ lấy danh sách user ID, không lấy thông tin chi tiết - Nhanh hơn * * @param accessToken Access token của OA * @param filters Bộ lọc tùy chọn * @returns Promise<string[]> - Danh sách user IDs */ async getAllUserIds(accessToken, filters) { const userIds = []; let offset = 0; const count = 50; // Max per request let totalUsers = 0; try { while (true) { const userListResponse = await this.getUserList(accessToken, { offset, count, ...filters, }); // Lần đầu tiên, lưu tổng số users if (offset === 0) { totalUsers = userListResponse.total; console.log(`Total user IDs to fetch: ${totalUsers}`); // Cảnh báo nếu vượt quá giới hạn Zalo API if (totalUsers > 10000) { console.warn(`Warning: Total users (${totalUsers}) exceeds Zalo API limit (10000). ` + `Only first 10000 users can be fetched due to max offset = 9951.`); } } // Chỉ lấy user IDs, không lấy detailed info const currentUserIds = userListResponse.users.map((u) => u.user_id); userIds.push(...currentUserIds); console.log(`Fetched ${userIds.length}/${Math.min(totalUsers, 10000)} user IDs`); // Điều kiện dừng if (userListResponse.users.length === 0 || userIds.length >= Math.min(totalUsers, 10000) || userListResponse.users.length < count) { break; } offset += count; // Protection: Tránh infinite loop if (offset > 9951) { console.warn("Reached Zalo maximum offset limit (9951), stopping pagination"); break; } } console.log(`Successfully fetched ${userIds.length} user IDs`); return userIds; } catch (error) { if (error instanceof common_1.ZaloSDKError) { throw error; } this.handleError(error, "Failed to get all user IDs"); } } /** * Cập nhật chi tiết người dùng * Endpoint: https://openapi.zalo.me/v3.0/oa/user/update * Method: POST * * @param accessToken OA access token * @param request Update user request with user_id and optional fields * @returns Promise<boolean> - true if successful */ async updateUser(accessToken, request) { try { const result = await this.client.apiPost(this.endpoints.user.update, accessToken, request); if (result.error !== 0) { throw new common_1.ZaloSDKError(result.message || "Failed to update user", result.error, result); } return true; } catch (error) { if (error instanceof common_1.ZaloSDKError) { throw error; } throw new common_1.ZaloSDKError(`Failed to update user: ${error.message}`, -1, error); } } /** * Xóa thông tin người dùng * Endpoint: https://openapi.zalo.me/v2.0/oa/deletefollowerinfo * Method: POST * * @param accessToken OA access token * @param userId User ID to delete info for * @returns Promise<boolean> - true if successful * * Note: Chỉ xóa thông tin lưu trữ ở phía OA, không thay đổi tài khoản Zalo */ async deleteUserInfo(accessToken, userId) { try { const request = { user_id: userId }; const result = await this.client.apiPost(this.endpoints.user.delete, accessToken, request); if (result.error !== 0) { throw new common_1.ZaloSDKError(result.message || "Failed to delete user info", result.error, result); } return true; } catch (error) { if (error instanceof common_1.ZaloSDKError) { throw error; } throw new common_1.ZaloSDKError(`Failed to delete user info: ${error.message}`, -1, error); } } /** * Truy xuất thông tin tùy biến của người dùng * Endpoint: https://openapi.zalo.me/v3.0/oa/user/detail/custominfo * Method: GET with data parameter as JSON string * * @param accessToken OA access token * @param request Get custom info request with user_id and optional fields_to_export * @returns Promise<UserCustomInfoResponse> - Custom info data * * Note: Tất cả giá trị trong custom_info đều được trả về dưới dạng string */ async getUserCustomInfo(accessToken, request) { try { // Build data object according to API spec const dataObject = { user_id: request.user_id, ...(request.fields_to_export && { fields_to_export: request.fields_to_export, }), }; // Send data as JSON string parameter according to API spec const params = { data: JSON.stringify(dataObject), }; const result = await this.client.apiGet(this.endpoints.user.getCustomInfo, accessToken, params); if (result.error !== 0) { throw new common_1.ZaloSDKError(result.message || "Failed to get user custom info", result.error, result); } return result; } catch (error) { if (error instanceof common_1.ZaloSDKError) { throw error; } throw new common_1.ZaloSDKError(`Failed to get user custom info: ${error.message}`, -1, error); } } /** * Cập nhật thông tin tùy biến của người dùng * Endpoint: https://openapi.zalo.me/v3.0/oa/user/update/custominfo * Method: POST * * @param accessToken OA access token * @param request Update custom info request with user_id and custom_info * @returns Promise<boolean> - true if successful * * Note: Cấu trúc custom_info phụ thuộc vào thiết lập OA */ async updateUserCustomInfo(accessToken, request) { try { const result = await this.client.apiPost(this.endpoints.user.updateCustomInfo, accessToken, request); if (result.error !== 0) { throw new common_1.ZaloSDKError(result.message || "Failed to update user custom info", result.error, result); } return true; } catch (error) { if (error instanceof common_1.ZaloSDKError) { throw error; } throw new common_1.ZaloSDKError(`Failed to update user custom info: ${error.message}`, -1, error); } } /** * Lấy danh sách nhãn * Endpoint: https://openapi.zalo.me/v2.0/oa/tag/gettagsofoa * Method: GET * * @param accessToken OA access token * @returns Promise<string[]> - Array of tag names */ async getLabels(accessToken) { try { const result = await this.client.apiGet(this.endpoints.tag.getList, accessToken); if (result.error !== 0) { throw new common_1.ZaloSDKError(result.message || "Failed to get labels", result.error, result); } return result.data || []; } catch (error) { if (error instanceof common_1.ZaloSDKError) { throw error; } throw new common_1.ZaloSDKError(`Failed to get labels: ${error.message}`, -1, error); } } /** * Gắn nhãn người dùng * Endpoint: https://openapi.zalo.me/v2.0/oa/tag/tagfollower * * @param accessToken OA access token * @param request Tag user request with user_id and tag_name * @returns Promise<boolean> - true if successful * * Note: Nếu tag_name không tồn tại, API sẽ tự động tạo nhãn mới */ async addTagToUser(accessToken, request) { try { const result = await this.client.apiPost(this.endpoints.tag.addToUser, accessToken, request); if (result.error !== 0) { throw new common_1.ZaloSDKError(result.message || "Failed to add tag to user", result.error, result); } return true; } catch (error) { if (error instanceof common_1.ZaloSDKError) { throw error; } throw new common_1.ZaloSDKError(`Failed to add tag to user: ${error.message}`, -1, error); } } /** * Gỡ nhãn người dùng * Endpoint: https://openapi.zalo.me/v2.0/oa/tag/rmfollowerfromtag * * @param accessToken OA access token * @param request Remove tag request with user_id and tag_name * @returns Promise<boolean> - true if successful */ async removeTagFromUser(accessToken, request) { try { const result = await this.client.apiPost(this.endpoints.tag.removeFromUser, accessToken, request); if (result.error !== 0) { throw new common_1.ZaloSDKError(result.message || "Failed to remove tag from user", result.error, result); } return true; } catch (error) { if (error instanceof common_1.ZaloSDKError) { throw error; } throw new common_1.ZaloSDKError(`Failed to remove tag from user: ${error.message}`, -1, error); } } /** * Xóa nhãn * Endpoint: https://openapi.zalo.me/v2.0/oa/tag/rmtag * Method: POST * * @param accessToken OA access token * @param tagName Tag name to delete * @returns Promise<boolean> - true if successful */ async deleteLabel(accessToken, tagName) { try { const request = { tag_name: tagName }; const result = await this.client.apiPost(this.endpoints.tag.delete, accessToken, request); if (result.error !== 0) { throw new common_1.ZaloSDKError(result.message || "Failed to delete label", result.error, result); } return true; } catch (error) { if (error instanceof common_1.ZaloSDKError) { throw error; } throw new common_1.ZaloSDKError(`Failed to delete label: ${error.message}`, -1, error); } } /** * Get users by tag */ async getUsersByTag(accessToken, tagName, offset = 0, count = 50) { return this.getUserList(accessToken, { offset, count, tag_name: tagName, }); } /** * Get followers only */ async getFollowers(accessToken, offset = 0, count = 50) { return this.getUserList(accessToken, { offset, count, is_follower: true, }); } /** * Get users by interaction period */ async getUsersByInteraction(accessToken, period, offset = 0, count = 50) { return this.getUserList(accessToken, { offset, count, last_interaction_period: period, }); } /** * Bulk tag operations */ async bulkAddTag(accessToken, userIds, tagName) { const results = { success: [], failed: [], }; for (const userId of userIds) { try { await this.addTagToUser(accessToken, { user_id: userId, tag_name: tagName, }); results.success.push(userId); } catch (error) { results.failed.push(userId); } } return results; } /** * Bulk remove tag operations */ async bulkRemoveTag(accessToken, userIds, tagName) { const results = { success: [], failed: [], }; for (const userId of userIds) { try { await this.removeTagFromUser(accessToken, { user_id: userId, tag_name: tagName, }); results.success.push(userId); } catch (error) { results.failed.push(userId); } } return results; } handleError(error, message) { const errorMessage = error instanceof Error ? error.message : "Unknown error"; throw new common_1.ZaloSDKError(`${message}: ${errorMessage}`, -1, error); } } exports.UserService = UserService; //# sourceMappingURL=user.service.js.map