u
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { getStore } from './store.js';
|
||||
|
||||
export async function createUnderParent({ googleAuthId, parentId, name, track_stock }) {
|
||||
export async function createUnderParent({ googleAuthId, parentId, name, track_stock, sku }) {
|
||||
const store = await getStore();
|
||||
return store.article.createUnderParent({ googleAuthId, parentId, name, track_stock });
|
||||
return store.article.createUnderParent({ googleAuthId, parentId, name, track_stock, sku });
|
||||
}
|
||||
|
||||
export async function getBySku(googleAuthId, sku) {
|
||||
|
||||
36
src/db/modelconversation.js
Normal file
36
src/db/modelconversation.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import { getStore } from './store.js';
|
||||
|
||||
export async function list(googleAuthId) {
|
||||
const store = await getStore();
|
||||
return store.modelconversation.list(googleAuthId);
|
||||
}
|
||||
|
||||
export async function create(googleAuthId, data) {
|
||||
const store = await getStore();
|
||||
return store.modelconversation.create(googleAuthId, data);
|
||||
}
|
||||
|
||||
export async function get(googleAuthId, conversationId) {
|
||||
const store = await getStore();
|
||||
return store.modelconversation.get(googleAuthId, conversationId);
|
||||
}
|
||||
|
||||
export async function setState(googleAuthId, conversationId, state) {
|
||||
const store = await getStore();
|
||||
return store.modelconversation.setState(googleAuthId, conversationId, state);
|
||||
}
|
||||
|
||||
export async function listMessages(googleAuthId, conversationId) {
|
||||
const store = await getStore();
|
||||
return store.modelmessage.list(googleAuthId, conversationId);
|
||||
}
|
||||
|
||||
export async function addMessage(googleAuthId, conversationId, data) {
|
||||
const store = await getStore();
|
||||
return store.modelmessage.add(googleAuthId, conversationId, data);
|
||||
}
|
||||
|
||||
export async function remove(googleAuthId, conversationId) {
|
||||
const store = await getStore();
|
||||
return store.modelconversation.delete(googleAuthId, conversationId);
|
||||
}
|
||||
26
src/db/modelvfs.js
Normal file
26
src/db/modelvfs.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { getStore } from './store.js';
|
||||
|
||||
export async function write(googleAuthId, input) {
|
||||
const store = await getStore();
|
||||
return store.modelvfs.write(googleAuthId, input);
|
||||
}
|
||||
|
||||
export async function read(googleAuthId, name) {
|
||||
const store = await getStore();
|
||||
return store.modelvfs.read(googleAuthId, name);
|
||||
}
|
||||
|
||||
export async function list(googleAuthId) {
|
||||
const store = await getStore();
|
||||
return store.modelvfs.list(googleAuthId);
|
||||
}
|
||||
|
||||
export async function remove(googleAuthId, name) {
|
||||
const store = await getStore();
|
||||
return store.modelvfs.delete(googleAuthId, name);
|
||||
}
|
||||
|
||||
export async function reset(googleAuthId) {
|
||||
const store = await getStore();
|
||||
return store.modelvfs.reset(googleAuthId);
|
||||
}
|
||||
498
src/db/publicCatalog.js
Normal file
498
src/db/publicCatalog.js
Normal file
@@ -0,0 +1,498 @@
|
||||
import { getProvider } from './store.js';
|
||||
|
||||
export async function getCompanyCatalogMeta(companyId) {
|
||||
const provider = await getProvider();
|
||||
const result = await provider.query(
|
||||
`SELECT
|
||||
id,
|
||||
name,
|
||||
root_category_id AS rootCategoryId,
|
||||
default_language_id AS languageId,
|
||||
poscustomergroup_id AS posCustomerGroupId
|
||||
FROM company
|
||||
WHERE id = @companyId`,
|
||||
{ companyId }
|
||||
);
|
||||
return result.rows[0] ?? null;
|
||||
}
|
||||
|
||||
export async function listCategories(companyId) {
|
||||
const company = await getCompanyCatalogMeta(companyId);
|
||||
if (!company) {
|
||||
throw new Error('Company not found');
|
||||
}
|
||||
if (!company.rootCategoryId) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const provider = await getProvider();
|
||||
const isSqlite = provider.dialect === 'sqlite3';
|
||||
|
||||
const sql = isSqlite
|
||||
? `WITH RECURSIVE tree AS (
|
||||
SELECT id, parent_id, sort
|
||||
FROM category
|
||||
WHERE id = @rootId
|
||||
UNION ALL
|
||||
SELECT c.id, c.parent_id, c.sort
|
||||
FROM category c
|
||||
INNER JOIN tree t ON c.parent_id = t.id
|
||||
)
|
||||
SELECT
|
||||
t.id,
|
||||
t.parent_id AS parentId,
|
||||
t.sort,
|
||||
ct.name,
|
||||
ct.slug,
|
||||
p.hash AS fullHash,
|
||||
p.thumbw AS thumbW,
|
||||
p.thumbh AS thumbH,
|
||||
p.thumbhash AS thumbHash
|
||||
FROM tree t
|
||||
LEFT JOIN categorytext ct
|
||||
ON ct.category_id = t.id AND ct.language_id = @languageId
|
||||
LEFT JOIN pic p ON p.id = (
|
||||
SELECT cp.pic_id
|
||||
FROM categorypic cp
|
||||
WHERE cp.category_id = t.id
|
||||
ORDER BY cp.sort, cp.id
|
||||
LIMIT 1
|
||||
)
|
||||
ORDER BY t.sort, t.id`
|
||||
: `WITH tree AS (
|
||||
SELECT id, parent_id, sort
|
||||
FROM category
|
||||
WHERE id = @rootId
|
||||
UNION ALL
|
||||
SELECT c.id, c.parent_id, c.sort
|
||||
FROM category c
|
||||
INNER JOIN tree t ON c.parent_id = t.id
|
||||
)
|
||||
SELECT
|
||||
t.id,
|
||||
t.parent_id AS parentId,
|
||||
t.sort,
|
||||
ct.name,
|
||||
ct.slug,
|
||||
p.hash AS fullHash,
|
||||
p.thumbw AS thumbW,
|
||||
p.thumbh AS thumbH,
|
||||
p.thumbhash AS thumbHash
|
||||
FROM tree t
|
||||
LEFT JOIN categorytext ct
|
||||
ON ct.category_id = t.id AND ct.language_id = @languageId
|
||||
OUTER APPLY (
|
||||
SELECT TOP 1 cp.pic_id
|
||||
FROM categorypic cp
|
||||
WHERE cp.category_id = t.id
|
||||
ORDER BY cp.sort ASC, cp.id ASC
|
||||
) first_pic
|
||||
LEFT JOIN pic p ON p.id = first_pic.pic_id
|
||||
ORDER BY t.sort, t.id`;
|
||||
|
||||
const result = await provider.query(sql, {
|
||||
rootId: company.rootCategoryId,
|
||||
languageId: company.languageId,
|
||||
});
|
||||
|
||||
return result.rows.map((row) => ({
|
||||
id: row.id,
|
||||
parentId: row.parentId,
|
||||
sort: row.sort,
|
||||
name: row.name ?? '',
|
||||
slug: row.slug ?? '',
|
||||
fullHash: row.fullHash ?? null,
|
||||
thumbW: row.thumbW ?? null,
|
||||
thumbH: row.thumbH ?? null,
|
||||
thumbHash: row.thumbHash ?? null,
|
||||
}));
|
||||
}
|
||||
|
||||
export async function listArticles(companyId, { categoryId, limit = 50, offset = 0, search } = {}) {
|
||||
const company = await getCompanyCatalogMeta(companyId);
|
||||
if (!company) {
|
||||
throw new Error('Company not found');
|
||||
}
|
||||
|
||||
const provider = await getProvider();
|
||||
const isSqlite = provider.dialect === 'sqlite3';
|
||||
|
||||
const safeLimit = Math.min(Math.max(1, Number(limit) || 50), 200);
|
||||
const safeOffset = Math.max(0, Number(offset) || 0);
|
||||
const trimmedSearch = typeof search === 'string' ? search.trim() : '';
|
||||
|
||||
const params = {
|
||||
companyId,
|
||||
languageId: company.languageId,
|
||||
posCustomerGroupId: company.posCustomerGroupId,
|
||||
limit: safeLimit,
|
||||
offset: safeOffset,
|
||||
};
|
||||
|
||||
if (categoryId != null) {
|
||||
params.categoryId = Number(categoryId);
|
||||
}
|
||||
if (trimmedSearch) {
|
||||
params.searchPattern = `%${trimmedSearch}%`;
|
||||
}
|
||||
|
||||
const whereClauses = [
|
||||
'a.company_id = @companyId',
|
||||
'a.fatherarticle_id IS NULL',
|
||||
];
|
||||
if (categoryId != null) {
|
||||
whereClauses.push('ca.category_id = @categoryId');
|
||||
}
|
||||
if (trimmedSearch) {
|
||||
whereClauses.push('(a.sku LIKE @searchPattern OR at.name LIKE @searchPattern)');
|
||||
}
|
||||
const whereSql = whereClauses.join(' AND ');
|
||||
|
||||
const fromClause = categoryId != null
|
||||
? 'categoryarticle ca INNER JOIN article a ON a.id = ca.article_id'
|
||||
: 'article a';
|
||||
|
||||
const sql = isSqlite
|
||||
? `SELECT
|
||||
a.id,
|
||||
a.sku,
|
||||
at.name,
|
||||
at.slug,
|
||||
pr.net,
|
||||
t.rate AS taxRate,
|
||||
a.track_stock AS trackStock,
|
||||
pic.hash AS fullHash,
|
||||
pic.thumbw AS thumbW,
|
||||
pic.thumbh AS thumbH,
|
||||
pic.thumbhash AS thumbHash,
|
||||
b.id AS brandId,
|
||||
b.name AS brandName
|
||||
FROM ${fromClause}
|
||||
LEFT JOIN articletext at
|
||||
ON at.article_id = a.id AND at.language_id = @languageId
|
||||
LEFT JOIN price pr
|
||||
ON pr.article_id = a.id
|
||||
AND pr.customergroup_id = @posCustomerGroupId
|
||||
AND pr.minmultiplier = 1
|
||||
LEFT JOIN tax t ON t.id = pr.tax_id
|
||||
LEFT JOIN pic ON pic.id = (
|
||||
SELECT ap.pic_id
|
||||
FROM articlepic ap
|
||||
WHERE ap.article_id = a.id
|
||||
ORDER BY ap.sort, ap.id
|
||||
LIMIT 1
|
||||
)
|
||||
LEFT JOIN brand b ON b.id = a.brand_id
|
||||
WHERE ${whereSql}
|
||||
ORDER BY a.id
|
||||
LIMIT @limit OFFSET @offset`
|
||||
: `SELECT
|
||||
a.id,
|
||||
a.sku,
|
||||
at.name,
|
||||
at.slug,
|
||||
pr.net,
|
||||
t.rate AS taxRate,
|
||||
a.track_stock AS trackStock,
|
||||
pic.hash AS fullHash,
|
||||
pic.thumbw AS thumbW,
|
||||
pic.thumbh AS thumbH,
|
||||
pic.thumbhash AS thumbHash,
|
||||
b.id AS brandId,
|
||||
b.name AS brandName
|
||||
FROM ${fromClause}
|
||||
LEFT JOIN articletext at
|
||||
ON at.article_id = a.id AND at.language_id = @languageId
|
||||
LEFT JOIN price pr
|
||||
ON pr.article_id = a.id
|
||||
AND pr.customergroup_id = @posCustomerGroupId
|
||||
AND pr.minmultiplier = 1
|
||||
LEFT JOIN tax t ON t.id = pr.tax_id
|
||||
OUTER APPLY (
|
||||
SELECT TOP 1 ap.pic_id
|
||||
FROM articlepic ap
|
||||
WHERE ap.article_id = a.id
|
||||
ORDER BY ap.sort ASC, ap.id ASC
|
||||
) first_pic
|
||||
LEFT JOIN pic ON pic.id = first_pic.pic_id
|
||||
LEFT JOIN brand b ON b.id = a.brand_id
|
||||
WHERE ${whereSql}
|
||||
ORDER BY a.id
|
||||
OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY`;
|
||||
|
||||
const result = await provider.query(sql, params);
|
||||
|
||||
return result.rows.map((row) => {
|
||||
const net = row.net != null ? Number(row.net) : null;
|
||||
const taxRate = row.taxRate != null ? Number(row.taxRate) : null;
|
||||
const gross = net != null && taxRate != null ? +(net * (1 + taxRate / 100)).toFixed(2) : null;
|
||||
|
||||
return {
|
||||
id: row.id,
|
||||
sku: row.sku,
|
||||
name: row.name ?? '',
|
||||
slug: row.slug ?? '',
|
||||
net,
|
||||
taxRate,
|
||||
gross,
|
||||
trackStock: Boolean(row.trackStock ?? 1),
|
||||
brand: row.brandName
|
||||
? {
|
||||
id: row.brandId ?? null,
|
||||
name: row.brandName,
|
||||
}
|
||||
: null,
|
||||
fullHash: row.fullHash ?? null,
|
||||
thumbW: row.thumbW ?? null,
|
||||
thumbH: row.thumbH ?? null,
|
||||
thumbHash: row.thumbHash ?? null,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export async function getArticleBySku(companyId, sku) {
|
||||
const company = await getCompanyCatalogMeta(companyId);
|
||||
if (!company) {
|
||||
throw new Error('Company not found');
|
||||
}
|
||||
|
||||
const provider = await getProvider();
|
||||
const isSqlite = provider.dialect === 'sqlite3';
|
||||
|
||||
const sql = isSqlite
|
||||
? `SELECT
|
||||
a.id,
|
||||
a.sku,
|
||||
at.name,
|
||||
at.slug,
|
||||
at.desc AS description,
|
||||
a.unitamount,
|
||||
a.weight,
|
||||
a.track_stock AS trackStock,
|
||||
u.si AS unitSi,
|
||||
u.basesi AS unitBasesi,
|
||||
u.basesifactor AS unitBasesifactor,
|
||||
ut.symbol AS unitSymbol,
|
||||
ut.name AS unitName,
|
||||
b.id AS brandId,
|
||||
b.name AS brandName,
|
||||
brand_pic.hash AS brandFullHash,
|
||||
brand_pic.thumbw AS brandThumbW,
|
||||
brand_pic.thumbh AS brandThumbH,
|
||||
brand_pic.thumbhash AS brandThumbHash,
|
||||
a.is_father AS isFather,
|
||||
a.fatherarticle_id AS fatherArticleId,
|
||||
father.sku AS fatherSku
|
||||
FROM article a
|
||||
LEFT JOIN articletext at
|
||||
ON at.article_id = a.id AND at.language_id = @languageId
|
||||
LEFT JOIN unit u ON u.id = a.unit_id
|
||||
LEFT JOIN unittext ut
|
||||
ON ut.unit_id = u.id AND ut.language_id = @languageId
|
||||
LEFT JOIN brand b ON b.id = a.brand_id
|
||||
LEFT JOIN pic brand_pic ON brand_pic.id = (
|
||||
SELECT bp.pic_id
|
||||
FROM brandpic bp
|
||||
WHERE bp.brand_id = b.id
|
||||
ORDER BY bp.sort, bp.id
|
||||
LIMIT 1
|
||||
)
|
||||
LEFT JOIN article father ON father.id = a.fatherarticle_id
|
||||
WHERE a.sku = @sku AND a.company_id = @companyId`
|
||||
: `SELECT
|
||||
a.id,
|
||||
a.sku,
|
||||
at.name,
|
||||
at.slug,
|
||||
at.desc AS description,
|
||||
a.unitamount,
|
||||
a.weight,
|
||||
a.track_stock AS trackStock,
|
||||
u.si AS unitSi,
|
||||
u.basesi AS unitBasesi,
|
||||
u.basesifactor AS unitBasesifactor,
|
||||
ut.symbol AS unitSymbol,
|
||||
ut.name AS unitName,
|
||||
b.id AS brandId,
|
||||
b.name AS brandName,
|
||||
brand_pic.hash AS brandFullHash,
|
||||
brand_pic.thumbw AS brandThumbW,
|
||||
brand_pic.thumbh AS brandThumbH,
|
||||
brand_pic.thumbhash AS brandThumbHash,
|
||||
a.is_father AS isFather,
|
||||
a.fatherarticle_id AS fatherArticleId,
|
||||
father.sku AS fatherSku
|
||||
FROM article a
|
||||
LEFT JOIN articletext at
|
||||
ON at.article_id = a.id AND at.language_id = @languageId
|
||||
LEFT JOIN unit u ON u.id = a.unit_id
|
||||
LEFT JOIN unittext ut
|
||||
ON ut.unit_id = u.id AND ut.language_id = @languageId
|
||||
LEFT JOIN brand b ON b.id = a.brand_id
|
||||
OUTER APPLY (
|
||||
SELECT TOP 1 bp.pic_id
|
||||
FROM brandpic bp
|
||||
WHERE bp.brand_id = b.id
|
||||
ORDER BY bp.sort ASC, bp.id ASC
|
||||
) first_brand_pic
|
||||
LEFT JOIN pic brand_pic ON brand_pic.id = first_brand_pic.pic_id
|
||||
LEFT JOIN article father ON father.id = a.fatherarticle_id
|
||||
WHERE a.sku = @sku AND a.company_id = @companyId`;
|
||||
|
||||
const result = await provider.query(sql, {
|
||||
sku,
|
||||
companyId,
|
||||
languageId: company.languageId,
|
||||
});
|
||||
|
||||
const row = result.rows[0];
|
||||
if (!row) {
|
||||
throw new Error('Article not found');
|
||||
}
|
||||
|
||||
const articleId = row.id;
|
||||
|
||||
const [categoriesRes, photosRes, eansRes, pricesRes, variantsRes] = await Promise.all([
|
||||
provider.query(
|
||||
`SELECT ca.category_id AS categoryId, ct.name, ct.slug
|
||||
FROM categoryarticle ca
|
||||
LEFT JOIN categorytext ct ON ct.category_id = ca.category_id AND ct.language_id = @languageId
|
||||
WHERE ca.article_id = @articleId
|
||||
ORDER BY ca.category_id`,
|
||||
{ articleId, languageId: company.languageId }
|
||||
),
|
||||
provider.query(
|
||||
`SELECT
|
||||
ap.sort,
|
||||
p.hash AS fullHash,
|
||||
p.w AS fullW,
|
||||
p.h AS fullH,
|
||||
p.size AS fullSize,
|
||||
p.thumbw AS thumbW,
|
||||
p.thumbh AS thumbH,
|
||||
p.thumbhash AS thumbHash
|
||||
FROM articlepic ap
|
||||
INNER JOIN pic p ON p.id = ap.pic_id
|
||||
WHERE ap.article_id = @articleId
|
||||
ORDER BY ap.sort ASC, ap.id ASC`,
|
||||
{ articleId }
|
||||
),
|
||||
provider.query(
|
||||
`SELECT ae.ean
|
||||
FROM articleean ae
|
||||
WHERE ae.article_id = @articleId
|
||||
ORDER BY ae.ean`,
|
||||
{ articleId }
|
||||
),
|
||||
provider.query(
|
||||
`SELECT
|
||||
pr.minmultiplier,
|
||||
pr.net,
|
||||
t.rate AS taxRate
|
||||
FROM price pr
|
||||
INNER JOIN tax t ON t.id = pr.tax_id
|
||||
WHERE pr.article_id = @articleId
|
||||
AND pr.customergroup_id = @posCustomerGroupId
|
||||
ORDER BY pr.minmultiplier ASC`,
|
||||
{ articleId, posCustomerGroupId: company.posCustomerGroupId }
|
||||
),
|
||||
row.isFather
|
||||
? provider.query(
|
||||
`SELECT
|
||||
child.id,
|
||||
child.sku,
|
||||
child.fathersort,
|
||||
child.track_stock AS trackStock,
|
||||
child.unitamount,
|
||||
child.weight,
|
||||
at_child.name,
|
||||
at_child.slug,
|
||||
av.id AS attributeValueId,
|
||||
av.value AS attributeValue
|
||||
FROM article child
|
||||
LEFT JOIN articletext at_child ON at_child.article_id = child.id AND at_child.language_id = @languageId
|
||||
LEFT JOIN articleattributevalue aav ON aav.article_id = child.id
|
||||
LEFT JOIN attributevalue av ON av.id = aav.attributevalue_id
|
||||
WHERE child.fatherarticle_id = @articleId
|
||||
ORDER BY child.fathersort ASC, child.id ASC`,
|
||||
{ articleId, languageId: company.languageId }
|
||||
)
|
||||
: Promise.resolve({ rows: [] }),
|
||||
]);
|
||||
|
||||
const prices = pricesRes.rows.map((p) => {
|
||||
const net = p.net != null ? Number(p.net) : null;
|
||||
const taxRate = p.taxRate != null ? Number(p.taxRate) : null;
|
||||
const gross = net != null && taxRate != null ? +(net * (1 + taxRate / 100)).toFixed(2) : null;
|
||||
return {
|
||||
minmultiplier: p.minmultiplier,
|
||||
net,
|
||||
taxRate,
|
||||
gross,
|
||||
};
|
||||
});
|
||||
|
||||
const primaryPrice = prices[0] ?? null;
|
||||
|
||||
return {
|
||||
id: row.id,
|
||||
sku: row.sku,
|
||||
name: row.name ?? '',
|
||||
slug: row.slug ?? '',
|
||||
description: row.description ?? '',
|
||||
unitamount: row.unitamount,
|
||||
weight: row.weight,
|
||||
trackStock: Boolean(row.trackStock ?? 1),
|
||||
unit: row.unitSi
|
||||
? {
|
||||
si: row.unitSi,
|
||||
basesi: row.unitBasesi,
|
||||
basesifactor: row.unitBasesifactor,
|
||||
symbol: row.unitSymbol ?? null,
|
||||
name: row.unitName ?? null,
|
||||
}
|
||||
: null,
|
||||
brand: row.brandName
|
||||
? {
|
||||
id: row.brandId ?? null,
|
||||
name: row.brandName,
|
||||
fullHash: row.brandFullHash ?? null,
|
||||
thumbW: row.brandThumbW ?? null,
|
||||
thumbH: row.brandThumbH ?? null,
|
||||
thumbHash: row.brandThumbHash ?? null,
|
||||
}
|
||||
: null,
|
||||
price: primaryPrice,
|
||||
prices,
|
||||
categories: categoriesRes.rows.map((c) => ({
|
||||
id: c.categoryId,
|
||||
name: c.name ?? '',
|
||||
slug: c.slug ?? '',
|
||||
})),
|
||||
photos: photosRes.rows.map((p) => ({
|
||||
sort: p.sort,
|
||||
fullHash: p.fullHash,
|
||||
fullW: p.fullW,
|
||||
fullH: p.fullH,
|
||||
fullSize: p.fullSize,
|
||||
thumbW: p.thumbW,
|
||||
thumbH: p.thumbH,
|
||||
thumbHash: p.thumbHash,
|
||||
})),
|
||||
eans: eansRes.rows.map((e) => e.ean),
|
||||
isFather: Boolean(row.isFather),
|
||||
fatherSku: row.fatherSku ?? null,
|
||||
variants: variantsRes.rows.map((v) => ({
|
||||
id: v.id,
|
||||
sku: v.sku,
|
||||
sort: v.fathersort,
|
||||
name: v.name ?? '',
|
||||
slug: v.slug ?? '',
|
||||
attributeValueId: v.attributeValueId ?? null,
|
||||
attributeValue: v.attributeValue ?? null,
|
||||
unitamount: v.unitamount,
|
||||
weight: v.weight,
|
||||
trackStock: Boolean(v.trackStock ?? 1),
|
||||
})),
|
||||
};
|
||||
}
|
||||
@@ -44,6 +44,8 @@ const STORE_NAMESPACES = [
|
||||
'attributevalue',
|
||||
'articleattributevalue',
|
||||
'categoryattributevalue',
|
||||
'modelconversation',
|
||||
'modelmessage',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -148,6 +150,11 @@ export async function getStore() {
|
||||
return connecting;
|
||||
}
|
||||
|
||||
export async function getProvider() {
|
||||
await getStore();
|
||||
return provider;
|
||||
}
|
||||
|
||||
export async function ensureConnection() {
|
||||
await getStore();
|
||||
}
|
||||
@@ -159,3 +166,4 @@ export async function closeStore() {
|
||||
store = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user