@warriorteam/redai-zalo-sdk
Version:
Comprehensive TypeScript/JavaScript SDK for Zalo APIs - Official Account v3.0, ZNS with Full Type Safety, Consultation Service, Broadcast Service, Group Messaging with List APIs, Social APIs, Enhanced Article Management, Promotion Service v3.0 with Multip
854 lines • 36.6 kB
JavaScript
;
/**
* 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 chi tiết người dùng (bản dùng POST)
* Endpoint: https://openapi.zalo.me/v3.0/oa/user/detail
* Method: POST với body JSON
*
* @param accessToken OA access token
* @param userId ID người dùng cần lấy thông tin
* @returns Promise<UserInfo> - Thông tin chi tiết người dùng
*/
async postUserInfo(accessToken, userId) {
try {
// Tạo body JSON theo yêu cầu API
const body = {
user_id: userId,
};
// Gửi POST request thay vì GET
const result = await this.client.apiPost(this.endpoints.user.getDetail, accessToken, body);
// Kiểm tra lỗi từ API Zalo
if (result.error !== 0) {
throw new common_1.ZaloSDKError(result.message || "Failed to get user information (POST)", result.error, result);
}
// Kiểm tra dữ liệu trả về
if (!result.data) {
throw new common_1.ZaloSDKError("No user data received from POST request", -1);
}
return result.data;
}
catch (error) {
if (error instanceof common_1.ZaloSDKError) {
throw error;
}
this.handleError(error, "Failed to get user info (POST)");
}
}
/**
* 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: 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) {
console.log('[getAllUsers] Bắt đầu lấy danh sách users với filters:', filters);
const users = [];
let offset = 0;
const count = 50; // Max per request
let totalUsers = 0;
let fetchedUsers = 0;
let failedUsers = 0;
try {
while (true) {
console.log(`[getAllUsers] Đang lấy batch tại offset=${offset}, count=${count}`);
const userListResponse = await this.postUserList(accessToken, {
offset,
count,
...filters,
});
console.log(`[getAllUsers] Nhận được ${userListResponse.users.length} user IDs từ postUserList`);
// Lần đầu tiên, lưu tổng số users
if (offset === 0) {
totalUsers = userListResponse.total;
console.log(`[getAllUsers] ✓ 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(`[getAllUsers] ⚠ 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 (sequential to avoid rate limit)
// Xử lý tuần tự để tránh bị Zalo API rate limit
const userIds = userListResponse.users.map((u) => u.user_id);
console.log(`[getAllUsers] Bắt đầu lấy chi tiết cho ${userIds.length} users...`);
const userInfos = [];
for (let i = 0; i < userIds.length; i++) {
const userId = userIds[i];
console.log(`[getAllUsers] ├─ [${i + 1}/${userIds.length}] Đang lấy info cho user: ${userId}`);
try {
const userInfo = await this.postUserInfo(accessToken, userId);
userInfos.push(userInfo);
console.log(`[getAllUsers] │ ✓ Thành công: ${userInfo.display_name || 'N/A'}`);
}
catch (error) {
failedUsers++;
console.warn(`[getAllUsers] │ ⚠ Skip user ${userId} do lỗi: ${error.message}`);
// Tiếp tục với user tiếp theo thay vì throw error
}
// Small delay between requests to avoid rate limiting
if (i < userIds.length - 1) {
await new Promise((resolve) => setTimeout(resolve, 100));
}
}
console.log(`[getAllUsers] ✓ Hoàn thành lấy chi tiết ${userInfos.length} users trong batch này`);
users.push(...userInfos);
fetchedUsers += userInfos.length;
console.log(`[getAllUsers] 📊 Progress: Đã lấy ${fetchedUsers}/${totalUsers} users (${Math.round((fetchedUsers / totalUsers) * 100)}%)`);
// Đ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) {
console.log(`[getAllUsers] 🛑 Điều kiện dừng:`, {
noMoreUsers: userListResponse.users.length === 0,
reachedTotal: fetchedUsers >= totalUsers,
lastPage: userListResponse.users.length < count
});
break;
}
offset += count;
console.log(`[getAllUsers] ➡ Chuyển sang batch tiếp theo, offset=${offset}`);
// 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(`[getAllUsers] ⚠ Reached Zalo maximum offset limit (9951), stopping pagination`);
break;
}
}
console.log(`[getAllUsers] ✅ HOÀN THÀNH: Successfully fetched ${users.length}/${totalUsers} users` + (failedUsers > 0 ? ` (${failedUsers} failed/skipped)` : ''));
return users;
}
catch (error) {
console.error('[getAllUsers] ❌ LỖI:', {
message: error.message,
code: error.code || error.error,
offset: offset,
fetchedSoFar: fetchedUsers,
totalTarget: totalUsers
});
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.postUserList(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");
}
}
/**
* Get all users with advanced filtering based on UserInfo fields
* Lấy tất cả users với bộ lọc nâng cao dựa trên các trường của UserInfo
*
* @param accessToken Access token của OA
* @param filters Bộ lọc nâng cao
* @returns Promise<UserInfo[]> - Danh sách users đã được lọc
*/
async getAllUsersWithAdvancedFilters(accessToken, filters = {}) {
try {
// Optimization: If only userIds filter is provided, get users directly
const hasOnlyUserIdsFilter = filters.userIds &&
filters.userIds.length > 0 &&
Object.keys(filters).length === 1;
if (hasOnlyUserIdsFilter) {
console.log(`Fetching ${filters.userIds.length} specific users by IDs`);
const userInfoPromises = filters.userIds.map((userId) => this.getUserInfo(accessToken, userId));
return await Promise.all(userInfoPromises);
}
// First get all users using basic Zalo API filters
const basicFilters = {
...(filters.tag_name && { tag_name: filters.tag_name }),
...(filters.last_interaction_period && {
last_interaction_period: filters.last_interaction_period,
}),
...(filters.is_follower !== undefined && {
is_follower: filters.is_follower,
}),
};
console.log("Fetching users with basic filters:", basicFilters);
const allUsers = await this.getAllUsers(accessToken, basicFilters);
// Apply advanced client-side filters
const filteredUsers = allUsers.filter((user) => {
// Filter by specific user IDs (exact match) - early return for performance
if (filters.userIds && filters.userIds.length > 0) {
if (!filters.userIds.includes(user.user_id)) {
return false;
}
}
// Filter by display name (contains)
if (filters.display_name_contains &&
!user.display_name
?.toLowerCase()
.includes(filters.display_name_contains.toLowerCase())) {
return false;
}
// Filter by user alias (contains)
if (filters.user_alias_contains &&
!user.user_alias
?.toLowerCase()
.includes(filters.user_alias_contains.toLowerCase())) {
return false;
}
// Filter by sensitive status
if (filters.is_sensitive !== undefined &&
user.is_sensitive !== filters.is_sensitive) {
return false;
}
// Filter by interaction date range
if (filters.last_interaction_date_range) {
const userDate = this.parseDate(user.user_last_interaction_date);
const fromDate = this.parseDate(filters.last_interaction_date_range.from);
const toDate = this.parseDate(filters.last_interaction_date_range.to);
if (userDate < fromDate || userDate > toDate) {
return false;
}
}
// Filter by multiple tags (OR operation)
if (filters.tag_names && filters.tag_names.length > 0) {
const userTags = user.tags_and_notes_info.tag_names || [];
const hasAnyTag = filters.tag_names.some((tag) => userTags.includes(tag));
if (!hasAnyTag) {
return false;
}
}
// Filter by required all tags (AND operation)
if (filters.require_all_tags && filters.require_all_tags.length > 0) {
const userTags = user.tags_and_notes_info.tag_names || [];
const hasAllTags = filters.require_all_tags.every((tag) => userTags.includes(tag));
if (!hasAllTags) {
return false;
}
}
// Exclude users with specific tags
if (filters.exclude_tags && filters.exclude_tags.length > 0) {
const userTags = user.tags_and_notes_info.tag_names || [];
const hasExcludedTag = filters.exclude_tags.some((tag) => userTags.includes(tag));
if (hasExcludedTag) {
return false;
}
}
// Filter by notes content (contains)
if (filters.notes_contains) {
const userNotes = user.tags_and_notes_info.notes || [];
const hasNote = userNotes.some((note) => note.toLowerCase().includes(filters.notes_contains.toLowerCase()));
if (!hasNote) {
return false;
}
}
// Shared info filters
if (user.shared_info) {
// Filter by city
if (filters.city &&
user.shared_info.city?.toLowerCase() !== filters.city.toLowerCase()) {
return false;
}
// Filter by district
if (filters.district &&
user.shared_info.district?.toLowerCase() !==
filters.district.toLowerCase()) {
return false;
}
// Filter by phone (contains)
if (filters.phone_contains &&
!user.shared_info.phone?.includes(filters.phone_contains)) {
return false;
}
// Filter by name (contains)
if (filters.name_contains &&
!user.shared_info.name
?.toLowerCase()
.includes(filters.name_contains.toLowerCase())) {
return false;
}
// Filter by address (contains)
if (filters.address_contains &&
!user.shared_info.address
?.toLowerCase()
.includes(filters.address_contains.toLowerCase())) {
return false;
}
// Filter by date of birth range
if (filters.dob_range && user.shared_info.user_dob) {
const userDob = this.parseDate(user.shared_info.user_dob);
const fromDob = this.parseDate(filters.dob_range.from);
const toDob = this.parseDate(filters.dob_range.to);
if (userDob < fromDob || userDob > toDob) {
return false;
}
}
// Filter by age range (calculated from dob)
if (filters.age_range && user.shared_info.user_dob) {
const userAge = this.calculateAge(user.shared_info.user_dob);
if (userAge < filters.age_range.min ||
userAge > filters.age_range.max) {
return false;
}
}
}
else {
// If user has no shared_info, filter out based on shared_info requirements
if (filters.city ||
filters.district ||
filters.phone_contains ||
filters.name_contains ||
filters.address_contains ||
filters.dob_range ||
filters.age_range) {
return false;
}
}
// Filter by external user ID (contains)
if (filters.external_id_contains &&
!user.user_external_id?.includes(filters.external_id_contains)) {
return false;
}
// Filter by has shared info
if (filters.has_shared_info !== undefined &&
!!user.shared_info !== filters.has_shared_info) {
return false;
}
// Filter by has phone
if (filters.has_phone !== undefined &&
!!user.shared_info?.phone !== filters.has_phone) {
return false;
}
// Filter by has address
if (filters.has_address !== undefined &&
!!user.shared_info?.address !== filters.has_address) {
return false;
}
return true;
});
console.log(`Applied advanced filters: ${allUsers.length} -> ${filteredUsers.length} users`);
return filteredUsers;
}
catch (error) {
if (error instanceof common_1.ZaloSDKError) {
throw error;
}
this.handleError(error, "Failed to get users with advanced filters");
}
}
/**
* Parse date from dd/MM/yyyy format to Date object
* Helper method cho các filter date
*/
parseDate(dateString) {
if (!dateString)
return new Date(0);
const [day, month, year] = dateString.split("/").map(Number);
return new Date(year, month - 1, day);
}
/**
* Calculate age from date of birth
* Helper method cho age filter
*/
calculateAge(dobString) {
if (!dobString)
return 0;
const dob = this.parseDate(dobString);
const today = new Date();
let age = today.getFullYear() - dob.getFullYear();
const monthDiff = today.getMonth() - dob.getMonth();
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < dob.getDate())) {
age--;
}
return age;
}
/**
* 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