umbot
Version:
Мультиплатформенный фреймворк для создания голосовых навыков и чат-ботов с единой бизнес-логикой. Встроенная поддержка ВКонтакте, Telegram, Viber, MAX, Яндекс Алисы, Маруси и Сбера SmartApp. Архитектура на адаптерах позволяет подключать любые другие платф
293 lines (292 loc) • 10.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.UsersData = void 0;
const Model_1 = require("./db/Model");
const RULES = [
{
name: ['userId'],
type: 'string',
max: 250,
},
{
name: ['meta', 'data'],
type: 'text',
},
{
name: ['platformName'],
type: 'string',
},
];
const ATTRS_LABEL = {
userId: 'ID',
meta: 'User meta data',
data: 'User Data',
platform: 'Platform Name',
};
/**
* Модель для работы с пользовательскими данными.
* Предоставляет единый интерфейс для работы с данными пользователей во всех поддерживаемых платформах.
*
* Основные возможности:
* - Сохранение состояния пользователя между сессиями
* - Хранение метаданных (например, статистика использования)
* - Поддержка как файлового хранилища, так и БД
* - Автоматическая сериализация/десериализация данных
*
* @example
* Сохранение прогресса пользователя:
* ```ts
* class GameController extends BotController {
* public async action(intentName: string): Promise<void> {
* // Загрузка данных пользователя
* const userData = new UsersData(this.appContext);
* userData.userId = this.userId;
*
* // Если есть сохраненные данные - загружаем их
* if (await userData.getOne()) {
* const progress = userData.data.progress || 0;
* this.text = `Ваш текущий прогресс: ${progress}%`;
* } else {
* // Создаем новые данные
* userData.data = { progress: 0 };
* userData.meta = { firstVisit: new Date() };
* await userData.save();
* this.text = 'Добро пожаловать в игру!';
* }
* }
* }
* ```
*
* @example
* Работа с разными платформами:
* ```ts
* const userData = new UsersData(appContext);
*
* // Для Алисы
* userData.platform = T_ALISA;
*
* // Для Telegram
* userData.platform = T_TELEGRAM;
* ```
*/
class UsersData extends Model_1.Model {
/**
* Название таблицы для хранения данных пользователей.
* @readonly
*/
static TABLE_NAME = 'UsersData';
/**
* Создает экземпляр модели пользовательских данных.
* Предоставляет унифицированный интерфейс для хранения данных пользователя.
*
* @example
* ```ts
* const userData = new UsersData(appContext);
* userData.userId = 'user123';
* userData.type = UsersData.T_TELEGRAM;
* ```
*/
constructor(appContext) {
super(appContext);
this.state = {
userId: null,
meta: null,
data: null,
platform: 'unknown',
};
}
getId() {
return 'userId';
}
/**
* Уникальный идентификатор пользователя.
* Может быть строкой или числом в зависимости от платформы.
* @example "123456789" для Telegram, 123456789 для VK
*/
get userId() {
return this.state.userId;
}
/**
* Устанавливает уникальный идентификатор пользователя.
* @param userId
*/
set userId(userId) {
this.state.userId = userId;
}
/**
* Метаданные пользователя.
* Может содержать любые дополнительные данные о пользователе, такие как:
* - Статистика использования
* - Временные метки
* - Настройки пользователя
* - Дополнительная информация
* @remarks При сохранении в БД автоматически преобразуется в JSON строку
*/
get meta() {
return this.state.meta;
}
/**
* Устанавливает метаданные пользователя.
* @param meta
*/
set meta(meta) {
this.state.meta = meta;
}
/**
* Основные данные пользователя.
* Содержит основное состояние пользователя, например:
* - Прогресс в игре
* - Сохраненные настройки
* - История действий
* - Другие пользовательские данные
* @remarks При сохранении в БД автоматически преобразуется в JSON строку
*/
get data() {
return this.state.data;
}
/**
* Устанавливает основные данные пользователя.
* @param data
*/
set data(data) {
this.state.data = data;
}
/**
* Тип платформы пользователя.
* Определяет платформу, с которой работает пользователь.
*/
set platform(platform) {
this.state.platform = platform;
}
/**
* Тип платформы пользователя.
* Определяет платформу, с которой работает пользователь.
*/
get platform() {
return this.state.platform;
}
/**
* Возвращает название таблицы/файла для хранения данных.
*
* @return {string} Название таблицы для хранения данных пользователей
*/
tableName() {
return UsersData.TABLE_NAME;
}
/**
* Определяет правила валидации полей модели.
*
* @return {IModelRules[]} Массив правил валидации
*/
rules() {
return RULES;
}
/**
* Возвращает описания атрибутов модели.
* Используется для отображения понятных названий полей.
*
* @return {IUserDataModelState} Описания атрибутов
*/
attributeLabels() {
return ATTRS_LABEL;
}
/**
* Ищет одну запись в хранилище по текущим параметрам.
*
* @return {Promise<boolean>} true, если запись найдена
*
* @example
* ```ts
* const userData = new UsersData(appContext);
* userData.userId = 'user123';
* if (await userData.getOne()) {
* console.log('Пользователь найден:', userData.data);
* } else {
* console.log('Пользователь не найден');
* }
* ```
*/
async getOne() {
const query = await this.selectOne();
if (query && query.status && this._appContext.database.adapter) {
this.init(this._appContext.database.adapter.getValue(query));
return true;
}
return false;
}
safeStringify(obj) {
const seen = new WeakSet();
return JSON.stringify(obj, (_, value) => {
if (typeof value === 'object' && value !== null) {
if (seen.has(value))
return '[Circular]';
seen.add(value);
}
return value;
});
}
/**
* Валидирует значения перед сохранением.
* Преобразует объекты meta и data в JSON при сохранении в БД.
*
* @throws {Error} Если данные не прошли валидацию
*
* @example
* ```ts
* userData.meta = { lastVisit: new Date() };
* userData.data = { progress: 75 };
* userData.validate(); // meta и data будут преобразованы в JSON
* ```
*/
validate() {
if (this.meta && typeof this.meta !== 'string') {
this.meta = this.safeStringify(this.meta);
}
if (this.data && typeof this.data !== 'string') {
this.data = this.safeStringify(this.data);
}
super.validate();
}
/**
* Инициализирует модель данными.
* Преобразует JSON строки meta и data в объекты при загрузке из БД.
*
* @param data - Данные для инициализации
* @remarks
* - При парсинге data, ошибки игнорируются для обеспечения обратной совместимости
* - Парсинг происходит только если включено сохранение в БД (appContext.isSaveDb === true)
*
* @example
* ```ts
* const userData = new UsersData(appContext);
* userData.init({
* userId: 'user123',
* meta: '{"lastVisit":"2024-03-20T12:00:00Z"}',
* data: '{"progress":75}',
* platform: T_TELEGRAM
* });
* console.log(userData.meta.lastVisit); // Date object
* console.log(userData.data.progress); // 75
* ```
*/
init(data) {
super.init(data);
if (typeof this.meta === 'string') {
if (this.meta.startsWith('{') || this.meta.startsWith('[')) {
this.meta = JSON.parse(this.meta);
}
}
if (typeof this.data === 'string') {
try {
this.data = JSON.parse(this.data);
}
catch (e) {
this._appContext?.logError(`UserData:init() Произошла ошибка при обработке данных. Скорей всего данные повреждены.`, {
error: e,
data: this.data,
});
}
}
}
}
exports.UsersData = UsersData;