done with upgrades..... I believe

This commit is contained in:
bootunloader
2025-01-25 23:41:57 +02:00
parent 15f2b238b0
commit aa73254a87
23 changed files with 2442 additions and 2368 deletions

View File

@@ -32,7 +32,7 @@
"ioredis": "^5.3.2", "ioredis": "^5.3.2",
"lucide-svelte": "^0.424.0", "lucide-svelte": "^0.424.0",
"node-fetch": "^3.3.2", "node-fetch": "^3.3.2",
"surrealdb.js": "^0.8.2", "surrealdb": "^1.1.0",
"svelte-french-toast": "^1.1.0", "svelte-french-toast": "^1.1.0",
"svelte-headlessui": "^0.0.20", "svelte-headlessui": "^0.0.20",
"tailwind-merge": "^2.4.0", "tailwind-merge": "^2.4.0",

50
pnpm-lock.yaml generated
View File

@@ -65,9 +65,9 @@ importers:
node-fetch: node-fetch:
specifier: ^3.3.2 specifier: ^3.3.2
version: 3.3.2 version: 3.3.2
surrealdb.js: surrealdb:
specifier: ^0.8.2 specifier: ^1.1.0
version: 0.8.4 version: 1.1.0(tslib@2.6.2)(typescript@5.2.2)(ws@8.14.2)
svelte-french-toast: svelte-french-toast:
specifier: ^1.1.0 specifier: ^1.1.0
version: 1.2.0(svelte@4.2.1) version: 1.2.0(svelte@4.2.1)
@@ -1141,6 +1141,11 @@ packages:
isexe@2.0.0: isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
isows@1.0.6:
resolution: {integrity: sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==}
peerDependencies:
ws: '*'
jiti@1.21.6: jiti@1.21.6:
resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==}
hasBin: true hasBin: true
@@ -1561,8 +1566,12 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
surrealdb.js@0.8.4: surrealdb@1.1.0:
resolution: {integrity: sha512-ToCyBHxpVPGXth31ZktQvv+s7fvZG6+sR3mXHNAlhq0/43yYiYx3+3cYvCDGZQNBNUI42KENv8/aBQ5mGQZEEA==} resolution: {integrity: sha512-EAopFKeIo1lVCR+XEE/oMuh8LCPAIa2xC9MyVs5nw+BJyHc0Fr6F/UWVF9399LRtTBCoqe5G1W0hgxqLqkWaYA==}
engines: {node: '>=18.0.0'}
peerDependencies:
tslib: ^2.6.3
typescript: ^5.0.0
svelte-check@3.5.2: svelte-check@3.5.2:
resolution: {integrity: sha512-5a/YWbiH4c+AqAUP+0VneiV5bP8YOk9JL3jwvN+k2PEPLgpu85bjQc5eE67+eIZBBwUEJzmO3I92OqKcqbp3fw==} resolution: {integrity: sha512-5a/YWbiH4c+AqAUP+0VneiV5bP8YOk9JL3jwvN+k2PEPLgpu85bjQc5eE67+eIZBBwUEJzmO3I92OqKcqbp3fw==}
@@ -1760,12 +1769,6 @@ packages:
unplugin@1.5.0: unplugin@1.5.0:
resolution: {integrity: sha512-9ZdRwbh/4gcm1JTOkp9lAkIDrtOyOxgHmY7cjuwI8L/2RTikMcVG25GsZwNAgRuap3iDw2jeq7eoqtAsz5rW3A==} resolution: {integrity: sha512-9ZdRwbh/4gcm1JTOkp9lAkIDrtOyOxgHmY7cjuwI8L/2RTikMcVG25GsZwNAgRuap3iDw2jeq7eoqtAsz5rW3A==}
unws@0.2.4:
resolution: {integrity: sha512-/N1ajiqrSp0A/26/LBg7r10fOcPtGXCqJRJ61sijUFoGZMr6ESWGYn7i0cwr7fR7eEECY5HsitqtjGHDZLAu2w==}
engines: {node: '>=16.14.0'}
peerDependencies:
ws: '*'
update-browserslist-db@1.1.0: update-browserslist-db@1.1.0:
resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==}
hasBin: true hasBin: true
@@ -1779,6 +1782,10 @@ packages:
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
hasBin: true hasBin: true
uuidv7@1.0.2:
resolution: {integrity: sha512-8JQkH4ooXnm1JCIhqTMbtmdnYEn6oKukBxHn1Ic9878jMkL7daTI7anTExfY18VRCX7tcdn5quzvCb6EWrR8PA==}
hasBin: true
vite-node@0.33.0: vite-node@0.33.0:
resolution: {integrity: sha512-19FpHYbwWWxDr73ruNahC+vtEdza52kA90Qb3La98yZ0xULqV8A5JLNPUff0f5zID4984tW7l3DH2przTJUZSw==} resolution: {integrity: sha512-19FpHYbwWWxDr73ruNahC+vtEdza52kA90Qb3La98yZ0xULqV8A5JLNPUff0f5zID4984tW7l3DH2przTJUZSw==}
engines: {node: '>=v14.18.0'} engines: {node: '>=v14.18.0'}
@@ -2830,6 +2837,10 @@ snapshots:
isexe@2.0.0: {} isexe@2.0.0: {}
isows@1.0.6(ws@8.14.2):
dependencies:
ws: 8.14.2
jiti@1.21.6: {} jiti@1.21.6: {}
jsonc-parser@3.2.0: {} jsonc-parser@3.2.0: {}
@@ -3202,13 +3213,14 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {} supports-preserve-symlinks-flag@1.0.0: {}
surrealdb.js@0.8.4: surrealdb@1.1.0(tslib@2.6.2)(typescript@5.2.2)(ws@8.14.2):
dependencies: dependencies:
unws: 0.2.4(ws@8.14.2) isows: 1.0.6(ws@8.14.2)
ws: 8.14.2 tslib: 2.6.2
typescript: 5.2.2
uuidv7: 1.0.2
transitivePeerDependencies: transitivePeerDependencies:
- bufferutil - ws
- utf-8-validate
svelte-check@3.5.2(postcss-load-config@4.0.1(postcss@8.4.40))(postcss@8.4.40)(svelte@4.2.1): svelte-check@3.5.2(postcss-load-config@4.0.1(postcss@8.4.40))(postcss@8.4.40)(svelte@4.2.1):
dependencies: dependencies:
@@ -3426,10 +3438,6 @@ snapshots:
webpack-sources: 3.2.3 webpack-sources: 3.2.3
webpack-virtual-modules: 0.5.0 webpack-virtual-modules: 0.5.0
unws@0.2.4(ws@8.14.2):
dependencies:
ws: 8.14.2
update-browserslist-db@1.1.0(browserslist@4.23.3): update-browserslist-db@1.1.0(browserslist@4.23.3):
dependencies: dependencies:
browserslist: 4.23.3 browserslist: 4.23.3
@@ -3440,6 +3448,8 @@ snapshots:
uuid@9.0.1: {} uuid@9.0.1: {}
uuidv7@1.0.2: {}
vite-node@0.33.0(@types/node@20.6.4): vite-node@0.33.0(@types/node@20.6.4):
dependencies: dependencies:
cac: 6.7.14 cac: 6.7.14

View File

@@ -1,36 +1,32 @@
import Surreal from "surrealdb.js"; import Surreal, { RecordId, StringRecordId } from "surrealdb";
export type { QueryResult } from "surrealdb.js/script/types"; export type { QueryResult } from "surrealdb";
try { try {
if (document || window) { if (document || window) {
throw new Error("SurrealDB needs a NodeJS environment to run."); throw new Error("SurrealDB needs a NodeJS environment to run.");
} }
} catch (err) {} } catch (err) {}
const CONFIG = { const CONFIG = {
url: process.env.SURREAL_URL ?? "", url: process.env.SURREAL_URL ?? "",
user: process.env.SURREAL_USER ?? "", user: process.env.SURREAL_USER ?? "",
pass: process.env.SURREAL_PASS ?? "", pass: process.env.SURREAL_PASS ?? "",
ns: process.env.SURREAL_NS ?? "", ns: process.env.SURREAL_NS ?? "",
db: process.env.SURREAL_DB ?? "", db: process.env.SURREAL_DB ?? "",
} as const; } as const;
// for (let key in CONFIG) { const db = new Surreal();
// if (
// !CONFIG[key as keyof typeof CONFIG] ||
// CONFIG[key as keyof typeof CONFIG] === ""
// ) {
// throw new Error(`Missing configuration for ${key}`);
// }
// }
let _surreal = export function parseToRID(idStr: string) {
CONFIG.url.length > 0 return new StringRecordId(idStr);
? new Surreal(`http://${CONFIG.url}/rpc`, { // const [a, b] = idStr.split(":");
auth: { user: CONFIG.user, pass: CONFIG.pass }, // return new RecordId(a, b);
ns: CONFIG.ns, }
db: CONFIG.db,
})
: undefined;
export const surreal = _surreal as Surreal; if (CONFIG.url.length > 0) {
await db.connect(`http://${CONFIG.url}/rpc`);
await db.use({ namespace: CONFIG.ns, database: CONFIG.db });
await db.signin({ username: CONFIG.user, password: CONFIG.pass });
}
export const surreal = db as Surreal;

View File

@@ -3,210 +3,279 @@ import { chunkArray } from "../array.chunk";
import { surreal } from "../connectors/surreal.db"; import { surreal } from "../connectors/surreal.db";
const getTableName = (date: string) => { const getTableName = (date: string) => {
return `apidata${date.replaceAll("-", "")}`; return `apidata${date.replaceAll("-", "")}`;
}; };
const upsertData = async ( const upsertData = async (
data: BookingEntry[], data: BookingEntry[],
date: string, date: string,
tries: number = 0, tries: number = 0,
): Promise<void> => { ): Promise<void> => {
const tableName = getTableName(date);
console.log(`[...] Upserting ${data.length} entries into ${tableName}`);
const alreadyPresentIds = new Set<string>();
try {
const [alreadyPresent] = await surreal.query<[string[]]>(
`select value id from type::table($tableName) where bookDate = $bookDate`,
{ tableName, bookDate: date },
);
for (let eId of alreadyPresent.result ?? []) {
alreadyPresentIds.add(eId);
}
} catch (err) {
console.log("Failed to fetch, seeing if can try again");
if (tries >= 3) { if (tries >= 3) {
console.log("Max tries exceeded for initial fetch for upserting data"); console.log("Max tries exceeded for processing data");
return; return;
} }
return await upsertData(data, date, tries++);
}
const oldEntries = [] as any[];
const newEntries = [] as BookingEntry[];
for (let entry of data) {
if (alreadyPresentIds.has(`${tableName}:${entry.id}`)) {
oldEntries.push({
distributorId: entry.distributorId,
dealerId: entry.dealerId,
drawId: entry.drawId,
bookDate: entry.bookDate.split(" ")[0],
number: entry.number,
first: entry.first,
second: entry.second,
changedBalance: entry.changedBalance,
sheetName: entry.sheetName,
sheetId: entry.sheetId,
requestId: entry.requestId,
updatedAt: new Date().toISOString(),
});
continue;
}
newEntries.push({
...entry,
id: `${tableName}:${entry.id}`,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
bookDate: entry.bookDate.split(" ")[0],
requestId: entry.requestId ?? "",
});
}
console.log(
`[+] Inserting ${newEntries.length} new entries into ${tableName}`,
);
// 5 to 25% of the total data length const tableName = getTableName(date);
let chunkSize = Math.floor( const drawId = data[0].drawId;
Math.random() * (data.length * 0.2 - data.length * 0.05) +
data.length * 0.05,
);
if (chunkSize > 10_000) {
chunkSize = 10_000;
}
console.log(`Chunk Size : ${chunkSize}`); console.log(`[...] Processing ${data.length} entries for ${tableName}`);
console.log(`[+] Inserting new entries`); try {
console.time("insertion time"); // Delete existing entries for this date
const chunks = chunkArray(newEntries, chunkSize).map(async (chunk) => { console.log(
await surreal.insert<BookingEntry>(tableName, chunk); `[...] Deleting existing entries for ${date} in ${tableName}`,
}); );
for (let i = 0; i < chunks.length; i += 2) { console.time("deletion time");
await Promise.all(chunks.slice(i, i + 2)); await surreal.query(
} `DELETE type::table($tableName) WHERE bookDate = $bookDate AND drawId = $drawId`,
console.timeEnd("insertion time"); { tableName, bookDate: date, drawId },
);
console.timeEnd("deletion time");
console.log( // Prepare new entries
`[+] Updating ${oldEntries.length} old entries into ${tableName}`, const entries = data.map((entry) => ({
); ...entry,
id: `${tableName}:${entry.id}`,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
bookDate: entry.bookDate.split(" ")[0],
requestId: entry.requestId ?? "",
}));
const chunks2 = chunkArray(oldEntries, chunkSize).map(async (chunk) => { // Calculate chunk size (5 to 25% of total data length, max 10,000)
await Promise.all( let chunkSize = Math.floor(
chunk.map(async (entry) => { Math.random() * (data.length * 0.2 - data.length * 0.05) +
// @ts-ignore data.length * 0.05,
await surreal.update<BookingEntry>(`${tableName}:${entry.id}`, { );
distributorId: entry.distributorId, if (chunkSize > 1_000) {
dealerId: entry.dealerId, chunkSize = 1_000;
drawId: entry.drawId, }
bookDate: entry.bookDate.split(" ")[0],
number: entry.number, console.log(`Chunk Size: ${chunkSize}`);
first: entry.first, console.log(
second: entry.second, `[+] Inserting ${entries.length} entries into ${tableName}`,
changedBalance: entry.changedBalance, );
sheetName: entry.sheetName,
sheetId: entry.sheetId, // Insert new entries in chunks
requestId: entry.requestId, console.time("insertion time");
updatedAt: new Date().toISOString(), const chunks = chunkArray(entries, chunkSize).map(async (chunk) => {
await surreal.insert<BookingEntry>(tableName, chunk);
}); });
}),
for (let i = 0; i < chunks.length; i += 2) {
await Promise.all(chunks.slice(i, i + 2));
}
console.timeEnd("insertion time");
console.log(
`[+] Successfully processed ${data.length} entries into ${tableName}`,
);
} catch (err) {
console.log("Failed to process data, attempting retry");
return await upsertData(data, date, tries + 1);
}
};
const upsertDataDED = async (
data: BookingEntry[],
date: string,
tries: number = 0,
): Promise<void> => {
const tableName = getTableName(date);
console.log(`[...] Upserting ${data.length} entries into ${tableName}`);
const alreadyPresentIds = new Set<string>();
try {
const [alreadyPresent] = await surreal.query<[string[]]>(
`select value id from type::table($tableName) where bookDate = $bookDate`,
{ tableName, bookDate: date },
);
for (let eId of alreadyPresent ?? []) {
alreadyPresentIds.add(eId);
}
} catch (err) {
console.log("Failed to fetch, seeing if can try again");
if (tries >= 3) {
console.log(
"Max tries exceeded for initial fetch for upserting data",
);
return;
}
return await upsertData(data, date, tries++);
}
const oldEntries = [] as any[];
const newEntries = [] as BookingEntry[];
for (let entry of data) {
if (alreadyPresentIds.has(`${tableName}:${entry.id}`)) {
oldEntries.push({
distributorId: entry.distributorId,
dealerId: entry.dealerId,
drawId: entry.drawId,
bookDate: entry.bookDate.split(" ")[0],
number: entry.number,
first: entry.first,
second: entry.second,
changedBalance: entry.changedBalance,
sheetName: entry.sheetName,
sheetId: entry.sheetId,
requestId: entry.requestId,
updatedAt: new Date().toISOString(),
});
continue;
}
newEntries.push({
...entry,
id: `${tableName}:${entry.id}`,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
bookDate: entry.bookDate.split(" ")[0],
requestId: entry.requestId ?? "",
});
}
console.log(
`[+] Inserting ${newEntries.length} new entries into ${tableName}`,
); );
});
console.time("update time"); // 5 to 25% of the total data length
for (let i = 0; i < chunks2.length; i += 10) { let chunkSize = Math.floor(
await Promise.all(chunks2.slice(i, i + 10)); Math.random() * (data.length * 0.2 - data.length * 0.05) +
} data.length * 0.05,
console.timeEnd("update time"); );
if (chunkSize > 10_000) {
chunkSize = 10_000;
}
console.log( console.log(`Chunk Size : ${chunkSize}`);
`[+] Successfully upserted ${data.length} entries into ${tableName}`,
); console.log(`[+] Inserting new entries`);
console.time("insertion time");
const chunks = chunkArray(newEntries, chunkSize).map(async (chunk) => {
await surreal.insert<BookingEntry>(tableName, chunk);
});
for (let i = 0; i < chunks.length; i += 2) {
await Promise.all(chunks.slice(i, i + 2));
}
console.timeEnd("insertion time");
console.log(
`[+] Updating ${oldEntries.length} old entries into ${tableName}`,
);
const chunks2 = chunkArray(oldEntries, chunkSize).map(async (chunk) => {
await Promise.all(
chunk.map(async (entry) => {
// @ts-ignore
await surreal.update<BookingEntry>(`${tableName}:${entry.id}`, {
distributorId: entry.distributorId,
dealerId: entry.dealerId,
drawId: entry.drawId,
bookDate: entry.bookDate.split(" ")[0],
number: entry.number,
first: entry.first,
second: entry.second,
changedBalance: entry.changedBalance,
sheetName: entry.sheetName,
sheetId: entry.sheetId,
requestId: entry.requestId,
updatedAt: new Date().toISOString(),
});
}),
);
});
console.time("update time");
for (let i = 0; i < chunks2.length; i += 10) {
await Promise.all(chunks2.slice(i, i + 10));
}
console.timeEnd("update time");
console.log(
`[+] Successfully upserted ${data.length} entries into ${tableName}`,
);
}; };
const getBookingEntriesForDealer = async ( const getBookingEntriesForDealer = async (
date: string, date: string,
drawId: string, drawId: string,
userId: string, userId: string,
sorted?: boolean, sorted?: boolean,
) => { ) => {
const tableName = getTableName(date); const tableName = getTableName(date);
let query = `select * from type::table($tableName) where bookDate = $date and dealerId = $userId and drawId = $drawId`; let query = `select * from type::table($tableName) where bookDate = $date and dealerId = $userId and drawId = $drawId`;
if (sorted) { if (sorted) {
query += " order by requestId desc"; query += " order by requestId desc";
} }
const [data] = await surreal.query<[BookingEntry[]]>(query, { const [data] = await surreal.query<[BookingEntry[]]>(query, {
tableName, tableName,
date: `${date}`, date: `${date}`,
userId: parseInt(userId), userId: parseInt(userId),
drawId: parseInt(drawId), drawId: parseInt(drawId),
}); });
console.log( console.log(
`Found ${JSON.stringify( `Found ${JSON.stringify(
data, data,
)} entries for ${userId}, filters are ${date}, ${drawId} for ${tableName}`, )} entries for ${userId}, filters are ${date}, ${drawId} for ${tableName}`,
); );
if (data.status === "OK") { return data ?? [];
return data.result ?? [];
}
return [];
}; };
const getBookingEntriesByDraw = async (date: string, drawId: string) => { const getBookingEntriesByDraw = async (date: string, drawId: string) => {
const tableName = getTableName(date); const tableName = getTableName(date);
const [data] = await surreal.query<[BookingEntry[]]>( const [data] = await surreal.query<[BookingEntry[]]>(
`select * from type::table($tableName) where bookDate = $date and drawId = $drawId`, `select * from type::table($tableName) where bookDate = $date and drawId = $drawId`,
{ {
tableName, tableName,
date: date, date: date,
drawId: parseInt(drawId.includes(":") ? drawId.split(":")[1] : drawId), drawId: parseInt(
}, drawId.includes(":") ? drawId.split(":")[1] : drawId,
); ),
if (data.status === "OK") { },
return data.result ?? []; );
} return data ?? [];
return [];
}; };
const deleteDataOlderThan2Weeks = async () => { const deleteDataOlderThan2Weeks = async () => {
const [out] = await surreal.query("info for db"); const [out] = await surreal.query("info for db");
// @ts-ignore // @ts-ignore
const tableNames = Object.keys(out.result.tables); const tableNames = Object.keys(out.result.tables);
const twoWeeksAgo = new Date(); const twoWeeksAgo = new Date();
twoWeeksAgo.setDate(twoWeeksAgo.getDate() - 14); twoWeeksAgo.setDate(twoWeeksAgo.getDate() - 14);
for (const tableName of tableNames) { for (const tableName of tableNames) {
if (tableName.startsWith("apidata")) { if (tableName.startsWith("apidata")) {
const datePart = tableName.slice(7); const datePart = tableName.slice(7);
const d = new Date( const d = new Date(
parseInt(datePart.slice(0, 4), 10), parseInt(datePart.slice(0, 4), 10),
parseInt(datePart.slice(4, 6), 10) - 1, // Month is 0-based in JavaScript Date parseInt(datePart.slice(4, 6), 10) - 1, // Month is 0-based in JavaScript Date
parseInt(datePart.slice(6, 8), 10), parseInt(datePart.slice(6, 8), 10),
); );
if (d < twoWeeksAgo) { if (d < twoWeeksAgo) {
console.log(`[...] Deleting ${tableName}`); console.log(`[...] Deleting ${tableName}`);
await surreal.query("remove table if exists " + tableName); await surreal.query("remove table if exists " + tableName);
console.log(`[+] Deleted ${tableName}`); console.log(`[+] Deleted ${tableName}`);
} }
} else if (tableName.startsWith("apipostdata_")) { } else if (tableName.startsWith("apipostdata_")) {
const datePart = tableName.slice(12); const datePart = tableName.slice(12);
const d = new Date( const d = new Date(
parseInt(datePart.slice(0, 4), 10), parseInt(datePart.slice(0, 4), 10),
parseInt(datePart.slice(4, 6), 10) - 1, // Month is 0-based in JavaScript Date parseInt(datePart.slice(4, 6), 10) - 1, // Month is 0-based in JavaScript Date
parseInt(datePart.slice(6, 8), 10), parseInt(datePart.slice(6, 8), 10),
); );
if (d < twoWeeksAgo) { if (d < twoWeeksAgo) {
console.log(`[...] Deleting ${tableName}`); console.log(`[...] Deleting ${tableName}`);
await surreal.query("remove table if exists " + tableName); await surreal.query("remove table if exists " + tableName);
console.log(`[+] Deleted ${tableName}`); console.log(`[+] Deleted ${tableName}`);
} }
} else { } else {
console.log(`Skipping ${tableName}`); console.log(`Skipping ${tableName}`);
}
} }
}
}; };
export const dbApiData = { export const dbApiData = {
upsertData, upsertData,
getBookingEntriesForDealer, getBookingEntriesForDealer,
getBookingEntriesByDraw, getBookingEntriesByDraw,
deleteDataOlderThan2Weeks, deleteDataOlderThan2Weeks,
}; };

View File

@@ -1,100 +1,101 @@
import { constants } from "$lib/utils/constants"; import { constants } from "$lib/utils/constants";
import type { Draw } from "$lib/utils/data.types"; import type { Draw } from "$lib/utils/data.types";
import { getDraws } from "../external/api.scraping.helpers"; import { getDraws } from "../external/api.scraping.helpers";
import { surreal } from "../connectors/surreal.db"; import { parseToRID, surreal } from "../connectors/surreal.db";
import { getSessionFromStore } from "../utils/session.service"; import { getSessionFromStore } from "../utils/session.service";
const tableName = "apidraw"; const tableName = "apidraw";
const _populateDrawsTable = async () => { const _populateDrawsTable = async () => {
const session = await getSessionFromStore(constants.SCRAP_API_SESSION_KEY); const session = await getSessionFromStore(constants.SCRAP_API_SESSION_KEY);
if (!session) { if (!session) {
return; return;
} }
const draws = await getDraws(session?.sessionToken); const draws = await getDraws(session?.sessionToken);
if (draws.data.length === 0 || !draws.ok) { if (draws.data.length === 0 || !draws.ok) {
return; return;
} }
await surreal.insert<Draw>( await surreal.insert<Draw>(
tableName, tableName,
draws.data.map((e) => { draws.data.map((e) => {
return { return {
id: e.id, id: e.id,
drawType: e.drawType, drawType: e.drawType,
adminId: e.adminId, adminId: e.adminId,
title: e.title, title: e.title,
closeTime: e.closeTime, closeTime: e.closeTime,
filterDuplicatesWhilePosting: false, filterDuplicatesWhilePosting: false,
abRateF: 0, abRateF: 0,
abcRateF: 0, abcRateF: 0,
abRateS: 0, abRateS: 0,
abcRateS: 0, abcRateS: 0,
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
}; };
}), }),
); );
}; };
const getAllDraws = async ( const getAllDraws = async (
skipOptional?: boolean, skipOptional?: boolean,
retry: number = 0, retry: number = 0,
): Promise<Draw[]> => { ): Promise<Draw[]> => {
let query = `select * from apidraw order by closeTime`; const [out] = await surreal.query<[Draw[]]>(
const [out] = await surreal.query<[Draw[]]>(query); `select * from apidraw order by closeTime`,
if (out.status === "OK") { );
const draws = out.result ?? []; if (out.length > 0) {
if (draws.length > 0) { return out;
return draws;
} }
await _populateDrawsTable(); await _populateDrawsTable();
if (retry < 3) { if (retry < 3) {
return getAllDraws(skipOptional, retry + 1); return getAllDraws(skipOptional, retry + 1);
} }
} return [];
return [];
}; };
async function setFilterDuplicatesFlag(drawId: string, flag: boolean) { async function setFilterDuplicatesFlag(drawId: string, flag: boolean) {
const [d] = await surreal.select<Draw>(drawId); const rid = parseToRID(drawId);
if (!d || !d.id) { const d = await surreal.select<Draw>(rid);
return; if (!d || !d.id) {
} return;
console.log("setFilterDuplicatesFlag :: ", drawId, flag); }
await surreal.update(drawId, { console.log("setFilterDuplicatesFlag :: ", rid, flag);
...d, await surreal.update(rid, {
filterDuplicatesWhilePosting: flag, ...d,
updatedAt: new Date().toISOString(), filterDuplicatesWhilePosting: flag,
} as Draw); updatedAt: new Date().toISOString(),
} as Draw);
} }
async function updateDrawPresetInfo(draw: Draw) { async function updateDrawPresetInfo(draw: Draw) {
const drawId = draw.id; const drawId = parseToRID(draw.id);
const [d] = await surreal.select<Draw>(drawId); const d = await surreal.select<Draw>(drawId);
if (!d || !d.id) { if (!d || !d.id) {
return; console.log(`Draw not present for ${drawId}`);
} return;
await surreal.update(drawId, { }
...d, console.log(`Updating draw info ${drawId}`);
filterDuplicatesWhilePosting: draw.filterDuplicatesWhilePosting, const out = await surreal.update(drawId, {
abRateF: draw.abRateF, ...d,
abcRateF: draw.abcRateF, filterDuplicatesWhilePosting: draw.filterDuplicatesWhilePosting,
abRateS: draw.abRateS, abRateF: draw.abRateF,
abcRateS: draw.abcRateS, abcRateF: draw.abcRateF,
updatedAt: new Date().toISOString(), abRateS: draw.abRateS,
} as Draw); abcRateS: draw.abcRateS,
updatedAt: new Date().toISOString(),
} as Draw);
} }
const getDraw = async (drawId: string): Promise<Draw | undefined> => { const getDraw = async (drawId: string): Promise<Draw | undefined> => {
const draws = await surreal.select<Draw>( const draws = await surreal.select<Draw>(
drawId.includes("apidraw") ? drawId : `apidraw:${drawId}`, parseToRID(drawId.includes("apidraw") ? drawId : `apidraw:${drawId}`),
); );
return draws[0]; return draws;
}; };
export const dbDraw = { export const dbDraw = {
getAllDraws, getAllDraws,
getDraw, getDraw,
setFilterDuplicatesFlag, setFilterDuplicatesFlag,
updateDrawPresetInfo, updateDrawPresetInfo,
}; };

View File

@@ -2,95 +2,98 @@ import type { PostDataEntry, PostDataHistory } from "$lib/utils/data.types";
import { surreal } from "../connectors/surreal.db"; import { surreal } from "../connectors/surreal.db";
const getTableName = (date: string) => { const getTableName = (date: string) => {
return `apipostdata_${date.replaceAll("-", "")}`; return `apipostdata_${date.replaceAll("-", "")}`;
}; };
const upsertData = async (data: PostDataHistory) => { const upsertData = async (data: PostDataHistory) => {
const tableName = getTableName(data.bookDate); const tableName = getTableName(data.bookDate);
const [check] = await surreal.query<[PostDataHistory[]]>( const [check] = await surreal.query<[PostDataHistory[]]>(
`select * from type::table($tableName) where bookDate = $bookDate and drawId = $drawId`, `select * from type::table($tableName) where bookDate = $bookDate and drawId = $drawId`,
{ tableName, bookDate: data.bookDate, drawId: data.drawId }, { tableName, bookDate: data.bookDate, drawId: data.drawId },
);
console.log(check);
const firstOut = check.result ? check.result[0] : undefined;
if (check.status === "OK" && !!firstOut && !!firstOut.id) {
console.log(
`Adding ${data.data.length} entries to ${firstOut.data.length} existing array`,
); );
firstOut.data.push(...data.data); console.log(check);
console.log(`Now have ${firstOut.data.length} entries in data list`); const firstOut = check && check.length > 0 ? check[0] : undefined;
console.log(`[...] Updating data row in db now`); if (check.length > 0 && !!firstOut && !!firstOut.id) {
await surreal.update<PostDataHistory>(firstOut.id, { console.log(
id: firstOut.id, `Adding ${data.data.length} entries to ${firstOut.data.length} existing array`,
data: firstOut.data, );
drawId: firstOut.drawId, firstOut.data.push(...data.data);
bookDate: firstOut.bookDate, console.log(`Now have ${firstOut.data.length} entries in data list`);
updatedAt: new Date().toISOString(), console.log(`[...] Updating data row in db now`);
}); await surreal.update<PostDataHistory>(firstOut.id, {
id: firstOut.id,
data: firstOut.data,
drawId: firstOut.drawId,
bookDate: firstOut.bookDate,
updatedAt: new Date().toISOString(),
});
return; return;
} }
await surreal.insert<PostDataHistory>(tableName, data); await surreal.insert<PostDataHistory>(tableName, data);
console.log( console.log(
`[+] Inserted post data in ${tableName} for ${data.bookDate} - ${data.drawId}`, `[+] Inserted post data in ${tableName} for ${data.bookDate} - ${data.drawId}`,
); );
}; };
const getPostDataByDraw = async (date: string, drawId: string) => { const getPostDataByDraw = async (date: string, drawId: string) => {
const tableName = getTableName(date); const tableName = getTableName(date);
const [data] = await surreal.query<[PostDataHistory[]]>( const [data] = await surreal.query<[PostDataHistory[]]>(
`select * from type::table($tableName) where bookDate = $date and drawId = $drawId`, `select * from type::table($tableName) where bookDate = $date and drawId = $drawId`,
{ {
tableName, tableName,
date: date, date,
drawId: parseInt(drawId.includes(":") ? drawId.split(":")[1] : drawId), drawId: parseInt(
}, drawId.includes(":") ? drawId.split(":")[1] : drawId,
); ),
let out = [] as PostDataEntry[]; },
if (data.status === "OK" && data.result.length > 0) { );
out = data.result[0].data; let out = [] as PostDataEntry[];
} if (data.length > 0) {
return out; out = data[0].data;
}
return out;
}; };
async function doesPostHistoryDataExist(date: string, drawId: string) { async function doesPostHistoryDataExist(date: string, drawId: string) {
const tableName = getTableName(date); const tableName = getTableName(date);
const [data] = await surreal.query<[PostDataHistory[]]>( const [data] = await surreal.query<[PostDataHistory[]]>(
`select id from type::table($tableName) where bookDate = $date and drawId = $drawId`, `select id from type::table($tableName) where bookDate = $date and drawId = $drawId`,
{ {
tableName, tableName,
date: date, date: date,
drawId: parseInt(drawId.includes(":") ? drawId.split(":")[1] : drawId), drawId: parseInt(
}, drawId.includes(":") ? drawId.split(":")[1] : drawId,
); ),
},
);
if (data.status === "OK") { return data[0]?.id.length > 0;
return data.result[0]?.id.length > 0;
}
return false;
} }
async function deletePostDataByDraw(date: string, drawId: string) { async function deletePostDataByDraw(date: string, drawId: string) {
const tableName = getTableName(date); const tableName = getTableName(date);
const [data] = await surreal.query<[PostDataHistory[]]>( const [data] = await surreal.query<[PostDataHistory[]]>(
`select id from type::table($tableName) where bookDate = $date and drawId = $drawId`, `select id from type::table($tableName) where bookDate = $date and drawId = $drawId`,
{ {
tableName, tableName,
date: date, date: date,
drawId: parseInt(drawId.includes(":") ? drawId.split(":")[1] : drawId), drawId: parseInt(
}, drawId.includes(":") ? drawId.split(":")[1] : drawId,
); ),
},
);
if (data.status === "OK") { if (data.length > 0) {
await surreal.delete(tableName); await surreal.delete(tableName);
return true; return true;
} }
return false; return false;
} }
export const dbApiPostData = { export const dbApiPostData = {
upsertData, upsertData,
getPostDataByDraw, getPostDataByDraw,
deletePostDataByDraw, deletePostDataByDraw,
doesPostHistoryDataExist, doesPostHistoryDataExist,
}; };

View File

@@ -1,281 +1,262 @@
import { import {
type ApiUser, type ApiUser,
type LooseApiUser, type LooseApiUser,
type ApiPostUser, type ApiPostUser,
type ApiPostUserWithParent, type ApiPostUserWithParent,
ApiUserTypes, ApiUserTypes,
DEFAULT_RANDOM_DISTRIBUTOR, DEFAULT_RANDOM_DISTRIBUTOR,
zApiPostUser,
} from "$lib/utils/data.types"; } from "$lib/utils/data.types";
import { surreal } from "../connectors/surreal.db"; import { parseToRID, surreal } from "../connectors/surreal.db";
const getUserById = async (userId: string) => { const getUserById = async (userId: string) => {
const query = `select * from apiuser where id = $id`; return await surreal.select<ApiUser>(parseToRID(userId));
const [rizzult] = await surreal.query<[ApiUser[]]>(query, { id: userId }); // const [rizzult] = await surreal.query<[ApiUser[]]>(query, { id: userId });
return rizzult.result?.[0]; // return rizzult[0];
}; };
const getAllIdsByUserType = async (userType: number) => { const getAllIdsByUserType = async (userType: number) => {
const query = `select value id from apiuser where userType = $userType`; const query = `select value id from apiuser where userType = $userType`;
const rizzult = (await surreal.query<[string[]]>(query, { userType }))[0]; const [rizzult] = await surreal.query<[any[]]>(query, { userType });
return (rizzult.result ?? []).map((e) => { return (rizzult ?? []).map((e) => {
return e.split(":")[1]; return e.id;
}); });
}; };
async function allUsersOfTypeLimitedInfo(userType: number) { async function allUsersOfTypeLimitedInfo(userType: number) {
const rizzult = ( const [rizzult] = await surreal.query<[ApiPostUser[]]>(
await surreal.query<[ApiPostUser[]]>( `select id,userName,userId,postData from apiuser where userType = $userType`,
`select id,userName,userId,postData from apiuser where userType = $userType`, { userType: userType },
{ userType: userType }, );
) return rizzult ?? [];
)[0];
if (rizzult.status == "OK") {
return rizzult.result ?? [];
}
return [];
} }
async function setPostDataFlagForUsers(users: ApiPostUser[]) { async function setPostDataFlagForUsers(users: ApiPostUser[]) {
for (const user of users) { for (const user of users) {
const [u] = await surreal.select<ApiUser>(user.id); const uid = parseToRID(user.id);
if (!u || !u.id) { const u = await surreal.select<ApiUser>(uid);
continue; if (!u || !u.id) {
continue;
}
console.log("Updating user :: ", uid);
await surreal.update<LooseApiUser>(uid, {
...u,
postData: user.postData ?? false,
});
} }
await surreal.update<LooseApiUser>(user.id, {
...u,
postData: user.postData ?? false,
});
}
} }
const getUserTypeCount = async (userType: number) => { const getUserTypeCount = async (userType: number) => {
const queryBase = `select count() from apiuser where userType = $userType`; const queryBase = `select count() from apiuser where userType = $userType`;
let query = `${queryBase} and disable = 0 group all`; let query = `${queryBase} and disable = 0 group all`;
let disabledQuery = `${queryBase} and disable = 1 group all`; let disabledQuery = `${queryBase} and disable = 1 group all`;
const enabledRizzult = ( const enabledRizzult = (
await surreal.query<[{ count: number }[]]>(query, { userType: userType }) await surreal.query<[{ count: number }[]]>(query, {
)[0]; userType: userType,
const count = { enabled: 0, disabled: 0 }; })
if (enabledRizzult.status == "OK") { )[0];
count.enabled = enabledRizzult.result[0]?.count ?? 0; const count = { enabled: 0, disabled: 0 };
} if (enabledRizzult.length > 0) {
const disabledRizzult = ( count.enabled = enabledRizzult[0]?.count ?? 0;
await surreal.query<[{ count: number }[]]>(disabledQuery, { }
userType: userType, const disabledRizzult = (
}) await surreal.query<[{ count: number }[]]>(disabledQuery, {
)[0]; userType: userType,
if (disabledRizzult.status == "OK") { })
count.disabled = disabledRizzult.result[0]?.count ?? 0; )[0];
} if (disabledRizzult.length > 0) {
return count; count.disabled = disabledRizzult[0]?.count ?? 0;
}
return count;
}; };
const allUsersOfType = async (userType: number) => { const allUsersOfType = async (userType: number) => {
const rizzult = ( const rizzult = (
await surreal.query<[ApiUser[]]>( await surreal.query<[ApiUser[]]>(
`select * from apiuser where userType = $userType`, `select * from apiuser where userType = $userType`,
{ userType: userType }, { userType: userType },
) )
)[0]; )[0];
if (rizzult.status == "OK") { return rizzult ?? [];
return rizzult.result ?? [];
}
return [];
}; };
async function updatePostUsersBalances( async function updatePostUsersBalances(
payload: { balance: number; id: string }[], payload: { balance: number; id: string }[],
) { ) {
console.log("Updating users balances"); console.log("Updating users balances");
console.log(payload); console.log(payload);
for (const each of payload) { for (const each of payload) {
const [rizzult] = await surreal.query<[ApiUser[]]>( const [rizzult] = await surreal.query<[ApiUser[]]>(
`update $userId set balance = $balance`, `update type::table($tableName) set balance = $balance`,
{ userId: each.id, balance: each.balance }, { tableName: each.id, balance: each.balance },
); );
if (rizzult.status !== "OK") { if (rizzult.length < 1) {
console.error("updatePostUsersBalance :: ", rizzult); console.error("updatePostUsersBalance :: ", rizzult);
}
} }
} console.log("Users balances updated");
console.log("Users balances updated");
} }
async function getAllPostUsers() { async function getAllPostUsers() {
const [rizzult] = await surreal.query<[ApiPostUser[]]>( const [rizzult] = await surreal.query<[ApiPostUser[]]>(
`select id,userName,userId,postData from apiuser where postData = true`, `select id,userName,userId,postData from apiuser where postData = true`,
); );
if (rizzult.status === "OK") { return rizzult ?? [];
return rizzult.result ?? [];
}
return [];
} }
async function getAllPostUsersWithParentUsers() { async function getAllPostUsersWithParentUsers() {
const [rizzult] = await surreal.query<[ApiPostUserWithParent[]]>( const [rizzult] = await surreal.query<[ApiPostUserWithParent[]]>(
`select id,userName,userId,postData,parentDistributor,parentAdmin from apiuser where postData = true`, `select id,userName,userId,postData,parentDistributor,parentAdmin from apiuser where postData = true`,
); );
if (rizzult.status === "OK") { const out = [];
return rizzult.result ?? []; for (const each of rizzult) {
} out.push({ ...each, id: each.id.toString() });
return []; }
return out;
// return rizzult ?? [];
} }
const getAllDistributorsWithTheirChildren = async () => {
const distributorIds = await getAllIdsByUserType(ApiUserTypes.DISTRIBUTOR);
const out = distributorIds.map(async (id) => {
const [rizzult] = await surreal.query<[ApiUser[]]>(
`select *, (select * from apiuser where parentDistributor = $id) as children from apiuser where id = $prefixedId`,
{ id, prefixedId: `apiuser:${id}` },
);
if (rizzult.status == "OK") {
return rizzult.result[0];
}
return undefined;
});
const responses = await Promise.all(out);
return responses;
};
const getRandomDistributor = async (): Promise<ApiUser> => { const getRandomDistributor = async (): Promise<ApiUser> => {
const ignoreList = ["001OP9"]; const ignoreList = ["001OP9"];
const randomUser = await _getRandomUser(ApiUserTypes.DISTRIBUTOR, ignoreList); const randomUser = await _getRandomUser(
if (!randomUser) { ApiUserTypes.DISTRIBUTOR,
console.log("getting random distributor...."); ignoreList,
return DEFAULT_RANDOM_DISTRIBUTOR; );
} if (!randomUser) {
return randomUser as any as ApiUser; console.log("getting random distributor....");
return DEFAULT_RANDOM_DISTRIBUTOR;
}
return randomUser as any as ApiUser;
}; };
const getRandomDealer = async (): Promise<ApiUser | undefined> => { const getRandomDealer = async (): Promise<ApiUser | undefined> => {
const ignoreList = ["rizgnore"]; const ignoreList = ["rizgnore"];
return _getRandomUser(ApiUserTypes.DEALER, ignoreList); return _getRandomUser(ApiUserTypes.DEALER, ignoreList);
}; };
const _getRandomUser = async ( const _getRandomUser = async (
userType: number, userType: number,
ignoreList: string[], ignoreList: string[],
): Promise<ApiUser | undefined> => { ): Promise<ApiUser | undefined> => {
console.log("_getRandomUser :: ", userType); console.log("_getRandomUser :: ", userType);
const rizzult = ( const [rizzult] = await surreal.query<[ApiUser[]]>(
await surreal.query<[ApiUser[]]>( `select * from apiuser where disable = 0 and userType = $userType and userId notinside $ignoreList order by rand() limit 1`,
`select * from apiuser where disable = 0 and userType = $userType and userId notinside $ignoreList order by rand() limit 1`, { userType: userType, ignoreList: ignoreList },
{ userType: userType, ignoreList: ignoreList }, );
)
)[0];
if (rizzult.status == "OK") {
console.log("found random user"); console.log("found random user");
return rizzult.result[0]; return rizzult[0];
}
}; };
const doesExist = async (userId?: string) => { const doesExist = async (userId?: string) => {
console.log("doesExist :: ", userId); console.log("doesExist :: ", userId);
if (userId) { if (userId) {
const [rizzult] = await surreal.query<{ count: number }[]>( const [rizzult] = await surreal.query<{ count: number }[]>(
"select count() from apiuser where userId = $userId group all", "select count() from apiuser where userId = $userId group all",
{ userId: userId }, { userId: userId },
); );
if (rizzult.status == "OK") { return rizzult?.count > 0;
return rizzult.result?.count > 0;
} }
} return false;
return false;
}; };
const insertMany = async (data: LooseApiUser[], postUsers: ApiPostUser[]) => { const insertMany = async (data: LooseApiUser[], postUsers: ApiPostUser[]) => {
console.log("insertMany :: ", data.length); console.log("insertMany :: ", data.length);
await surreal.insert<LooseApiUser>( await surreal.insert<LooseApiUser>(
"apiuser", "apiuser",
data.map((e) => { data.map((e) => {
return { return {
...e, ...e,
postData: !!postUsers.find((u) => u.userId === e.userId), postData: !!postUsers.find((u) => u.userId === e.userId),
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
}; };
}), }),
); );
}; };
async function upsertMany( async function upsertMany(
data: LooseApiUser[], data: LooseApiUser[],
wipeTable: boolean, wipeTable: boolean,
deleteUserType: typeof ApiUserTypes.DISTRIBUTOR | typeof ApiUserTypes.DEALER, deleteUserType:
| typeof ApiUserTypes.DISTRIBUTOR
| typeof ApiUserTypes.DEALER,
) { ) {
const postUsers = await getAllPostUsers(); const postUsers = await getAllPostUsers();
console.log(postUsers); console.log(postUsers);
if (wipeTable) { if (wipeTable) {
console.log("[wipeTable] :: deleting all previous users"); console.log("[wipeTable] :: deleting all previous users");
await surreal.query("delete from apiuser where userType = $userType", { await surreal.query("delete from apiuser where userType = $userType", {
userType: deleteUserType, userType: deleteUserType,
}); });
}
console.log("upsertMany :: ", data.length);
const toCreate = [] as LooseApiUser[];
const out = data.map(async (apiUser) => {
// INFO: if you do want to keep disabled users, remove this check
if (apiUser.disable === 1) {
return;
} }
const [u] = await surreal.select<ApiUser>(`apiuser:${apiUser.id}`); console.log("upsertMany :: ", data.length);
if (!u || !u.id) { const toCreate = [] as LooseApiUser[];
toCreate.push(apiUser); const out = data.map(async (apiUser) => {
return; // INFO: if you do want to keep disabled users, remove this check
} if (apiUser.disable === 1) {
let postData = return;
u.postData ?? !!postUsers.find((pu) => pu.userId === u.userId) ?? false; }
const qId = u.id; const uid = parseToRID(`apiuser:${apiUser.id}`);
await surreal.update<LooseApiUser>(qId, { const u = await surreal.select<ApiUser>(uid);
id: u.id, if (!u || !u.id) {
userId: apiUser.userId, toCreate.push(apiUser);
userType: apiUser.userType, return;
disableBooking: apiUser.disableBooking, }
sendVoucher: apiUser.sendVoucher, let postData =
voucherGenerated: apiUser.voucherGenerated, u.postData ??
parentAdmin: apiUser.parentAdmin, !!postUsers.find((pu) => pu.userId === u.userId) ??
parentDistributor: apiUser.parentDistributor, false;
userName: apiUser.userName, const qId = parseToRID(u.id);
userCity: apiUser.userCity, await surreal.update<LooseApiUser>(qId, {
password: apiUser.password, id: u.id,
accessDenied: apiUser.accessDenied, userId: apiUser.userId,
phoneNumber: apiUser.phoneNumber, userType: apiUser.userType,
emailAddress: apiUser.emailAddress, disableBooking: apiUser.disableBooking,
disable: apiUser.disable, sendVoucher: apiUser.sendVoucher,
commission: apiUser.commission, voucherGenerated: apiUser.voucherGenerated,
commissionPangora: apiUser.commissionPangora, parentAdmin: apiUser.parentAdmin,
allowTitles: apiUser.allowTitles, parentDistributor: apiUser.parentDistributor,
specialDealer: apiUser.specialDealer, userName: apiUser.userName,
allowBalance: apiUser.allowBalance, userCity: apiUser.userCity,
balance: apiUser.balance, password: apiUser.password,
profitlossShare: apiUser.profitlossShare, accessDenied: apiUser.accessDenied,
shareProfitonly: apiUser.shareProfitonly, phoneNumber: apiUser.phoneNumber,
allowRemoveold: apiUser.allowRemoveold, emailAddress: apiUser.emailAddress,
removeDays: apiUser.removeDays, disable: apiUser.disable,
language: apiUser.language, commission: apiUser.commission,
postData, commissionPangora: apiUser.commissionPangora,
createdAt: u.createdAt, allowTitles: apiUser.allowTitles,
updatedAt: new Date().toISOString(), specialDealer: apiUser.specialDealer,
allowBalance: apiUser.allowBalance,
balance: apiUser.balance,
profitlossShare: apiUser.profitlossShare,
shareProfitonly: apiUser.shareProfitonly,
allowRemoveold: apiUser.allowRemoveold,
removeDays: apiUser.removeDays,
language: apiUser.language,
postData,
createdAt: u.createdAt,
updatedAt: new Date().toISOString(),
});
}); });
}); await Promise.allSettled(out);
await Promise.allSettled(out); if (toCreate.length > 0) {
if (toCreate.length > 0) { await insertMany(toCreate, postUsers);
await insertMany(toCreate, postUsers); }
}
} }
export const dbApiUser = { export const dbApiUser = {
allUsersOfType, allUsersOfType,
allUsersOfTypeLimitedInfo, allUsersOfTypeLimitedInfo,
getUserById, getUserById,
getAllDistributorsWithTheirChildren, getUserTypeCount,
getUserTypeCount, getAllIdsByUserType,
getAllIdsByUserType, getAllPostUsers,
getAllPostUsers, getAllPostUsersWithParentUsers,
getAllPostUsersWithParentUsers, getRandomDistributor,
getRandomDistributor, getRandomDealer,
getRandomDealer, doesExist,
doesExist, upsertMany,
upsertMany, setPostDataFlagForUsers,
setPostDataFlagForUsers, updatePostUsersBalances,
updatePostUsersBalances,
}; };

View File

@@ -1,4 +0,0 @@
export const dbBooking = {
};

View File

@@ -1,40 +1,39 @@
import type { FinalSheetData } from "$lib/utils/data.types"; import type { FinalSheetData } from "$lib/utils/data.types";
import { surreal } from "../connectors/surreal.db"; import { parseToRID, surreal } from "../connectors/surreal.db";
const getTableName = (date: string) => { const getTableName = (date: string) => {
return `finalsheet${date.replaceAll("-", "")}`; return `finalsheet${date.replaceAll("-", "")}`;
}; };
const upsertData = async (data: FinalSheetData, date: string) => { const upsertData = async (data: FinalSheetData, date: string) => {
const tableName = getTableName(date); const tableName = getTableName(date);
const [present] = await surreal.query<[FinalSheetData[]]>( const [present] = await surreal.query<[FinalSheetData[]]>(
`select id from type::table($tableName) where date = $date and drawId = $drawId`, `select id from type::table($tableName) where date = $date and drawId = $drawId`,
{ tableName, date: `${date}`, drawId: data.drawId } { tableName, date: `${date}`, drawId: data.drawId },
); );
if (present) { const id = parseToRID(`${tableName}:${data.id}`);
// @ts-ignore if (present) {
await surreal.update<FinalSheetData>(`${tableName}:${data.id}`, { // @ts-ignore
date: data.date, await surreal.update<FinalSheetData>(id, {
drawId: data.drawId, date: data.date,
data: data.data, drawId: data.drawId,
totals: data.totals, data: data.data,
// @ts-ignore totals: data.totals,
createdAt: present?.result[0]?.createdAt ?? new Date().toISOString(), // @ts-ignore
updatedAt: new Date().toISOString(), createdAt: present[0]?.createdAt ?? new Date().toISOString(),
}); updatedAt: new Date().toISOString(),
} else { });
// @ts-ignore } else {
await surreal.create<FinalSheetData>(`${tableName}:${data.id}`, { // @ts-ignore
date: data.date, await surreal.create<FinalSheetData>(id, {
drawId: data.drawId, date: data.date,
data: data.data, drawId: data.drawId,
totals: data.totals, data: data.data,
createdAt: new Date().toISOString(), totals: data.totals,
updatedAt: new Date().toISOString(), createdAt: new Date().toISOString(),
}); updatedAt: new Date().toISOString(),
} });
}
}; };
export const dbFinalSheet = { export const dbFinalSheet = { upsertData };
upsertData,
};

View File

@@ -1,65 +1,62 @@
import type { import type { PresetDataEntry } from "$lib/utils/data.types";
ApiPostUser,
PostDataEntry,
PresetDataEntry,
} from "$lib/utils/data.types";
import { surreal } from "../connectors/surreal.db"; import { surreal } from "../connectors/surreal.db";
const getTableName = (date: string) => { const getTableName = (date: string) => {
return `presetdata_${date.replaceAll("-", "")}`; return `presetdata_${date.replaceAll("-", "")}`;
}; };
const insertData = async (data: PresetDataEntry[]) => { const insertData = async (data: PresetDataEntry[]) => {
if (data.length < 1) return; if (data.length < 1) return;
const tableName = getTableName(data[0].bookDate); const tableName = getTableName(data[0].bookDate);
const out = await surreal.insert<PresetDataEntry>(tableName, data); console.log(`Inserting ${data.length} rows in ${tableName}`);
console.log( const out = await surreal.insert<PresetDataEntry>(tableName, data);
`[+] Inserted post data in ${tableName} for ${data[0].bookDate} - ${data[0].drawId}`, console.log(
); `[+] Inserted post data in ${tableName} for ${data[0].bookDate} - ${data[0].drawId}`,
return out; );
return out;
}; };
const getDataByDraw = async (date: string, drawId: number) => { const getDataByDraw = async (date: string, drawId: number) => {
const tableName = getTableName(date); const tableName = getTableName(date);
const [data] = await surreal.query<[PresetDataEntry[]]>( const [data] = await surreal.query<[PresetDataEntry[]]>(
`select * from type::table($tableName) where bookDate = $date and drawId = $drawId`, `select * from type::table($tableName) where bookDate = $date and drawId = $drawId`,
{ tableName, date, drawId }, { tableName, date, drawId },
); );
return data.result || ([] as PresetDataEntry[]); return data || ([] as PresetDataEntry[]);
}; };
const getDataGroupedBySheetByDraw = async (date: string, drawId: number) => { const getDataGroupedBySheetByDraw = async (date: string, drawId: number) => {
const tableName = getTableName(date); const tableName = getTableName(date);
const [data] = await surreal.query<[PresetDataEntry[]]>( const [data] = await surreal.query<[PresetDataEntry[]]>(
`select * from type::table($tableName) where bookDate = $date and drawId = $drawId`, `select * from type::table($tableName) where bookDate = $date and drawId = $drawId`,
{ tableName, date, drawId }, { tableName, date, drawId },
); );
const out = { const out = {
abData: [] as PresetDataEntry[], abData: [] as PresetDataEntry[],
abcData: [] as PresetDataEntry[], abcData: [] as PresetDataEntry[],
all: data.result || ([] as PresetDataEntry[]), all: data || ([] as PresetDataEntry[]),
}; };
for (const row of data.result ?? []) { for (const row of data ?? []) {
if (row.number.length === 2) { if (row.number.length === 2) {
out.abData.push(row); out.abData.push(row);
} else if (row.number.length === 3) { } else if (row.number.length === 3) {
out.abcData.push(row); out.abcData.push(row);
}
} }
} return out;
return out;
}; };
async function deleteDataByIds(date: string, ids: string[]) { async function deleteDataByIds(date: string, ids: string[]) {
const tableName = getTableName(date); const tableName = getTableName(date);
await surreal.query<[PresetDataEntry[]]>( await surreal.query<[PresetDataEntry[]]>(
`delete from type::table($tableName) where id in $ids`, `delete from type::table($tableName) where id in $ids`,
{ tableName, ids }, { tableName, ids },
); );
} }
export const dbPresetData = { export const dbPresetData = {
insertData, insertData,
getDataGroupedBySheetByDraw, getDataGroupedBySheetByDraw,
getDataByDraw, getDataByDraw,
deleteDataByIds, deleteDataByIds,
}; };

View File

@@ -1,90 +1,76 @@
import type { User } from "$lib/utils/data.types"; import type { User } from "$lib/utils/data.types";
import { surreal, type QueryResult } from "../connectors/surreal.db"; import { surreal } from "../connectors/surreal.db";
export const dbUser = { export const dbUser = {
doesExist: async (username?: string) => { doesExist: async (username?: string) => {
if (username) { if (username) {
const [rizzult] = await surreal.query<{ count: number }[]>( const [rizzult] = await surreal.query<{ count: number }[]>(
"select count() from user where username = $username group all", "select count() from user where username = $username group all",
{ username: username } { username },
); );
if (rizzult.status == "OK") { return rizzult?.count > 0;
return rizzult.result?.count > 0; }
} return false;
} },
return false; create: async (data: {
}, username: string;
create: async (data: { password: string;
username: string; userType: string;
password: string; association: string;
userType: string; }) => {
association: string; const doesUserAlreadyExist = await dbUser.doesExist(data.username);
}) => { console.log("doesUserAlreadyExist :: ", doesUserAlreadyExist);
const doesUserAlreadyExist = await dbUser.doesExist(data.username); if (doesUserAlreadyExist) {
console.log("doesUserAlreadyExist :: ", doesUserAlreadyExist); return [{ message: "User already exists." }];
if (doesUserAlreadyExist) { }
return [{ message: "User already exists." }]; const { username, password, association, userType } = data;
} const out = await surreal.create<any>(`user`, {
const { username, password, association, userType } = data; createdAt: Date.now().toString(),
const out = await surreal.create<any>(`user:ulid()`, { updatedAt: Date.now().toString(),
createdAt: Date.now().toString(), username,
updatedAt: Date.now().toString(), password,
username, userType,
password, association,
userType, });
association, return out as User[];
}); },
return out as User[]; all: async () => {
}, return await surreal.select<User>("user");
all: async () => { },
return await surreal.select<User>("user"); get: async (d: {
}, username?: string;
get: async (d: { id?: string;
username?: string; }): Promise<User | undefined> => {
id?: string; if (d.id) {
}): Promise<User | undefined> => { return (await surreal.select<User>(`user:${d.id}`))[0];
if (d.id) { }
return (await surreal.select<User>(`user:${d.id}`))[0]; if (d.username) {
} const rizzult = (
if (d.username) { await surreal.query<[User[]]>(
const rizzult = ( `select * from user where username = $username`,
await surreal.query<[User[]]>( { username: d.username },
`select * from user where username = $username`, )
{ username: d.username } )[0];
) return rizzult[0];
)[0]; }
if (rizzult.status == "OK") { return undefined;
return rizzult.result[0]; },
} getChildren: async (username?: string) => {
} const [rizzult] = await surreal.query<User[]>(
return undefined; `select * from user where association = $username`,
}, { username: username },
getChildren: async (username?: string) => { );
const rizzult = await surreal.query<User[]>( return rizzult;
`select * from user where association = $username`, },
{ username: username } update: async (id: string, data: { association: string }) => {
); const [rizzult] = await surreal.update<User>(`user:${id}`, {
return getParsedUsers(rizzult); updatedAt: Date.now().toString(),
}, association: data.association,
update: async (id: string, data: { association: string }) => { } as User);
const [rizzult] = await surreal.update<User>(`user:${id}`, { return rizzult;
updatedAt: Date.now().toString(), },
association: data.association, delete: async (id: string) => {
} as User); const out = await surreal.delete(`user:${id}`);
return rizzult; return out[0].id;
}, },
delete: async (id: string) => {
const out = await surreal.delete(`user:${id}`);
return out[0].id;
},
};
const getParsedUsers = (data: QueryResult<User>[]) => {
const users = [] as User[];
for (const each of data) {
if (each.status == "OK") {
users.push(each.result);
}
}
return users;
}; };

View File

@@ -13,317 +13,317 @@ import { rng } from "$lib/utils/rng";
// } // }
export const testIfSessionIsValid = async (jwt: string) => { export const testIfSessionIsValid = async (jwt: string) => {
try { try {
const res = await fetch( const res = await fetch(
`${constants.SCRAP_API_URL}/v1/user/get-balance?userId=6339`, `${constants.SCRAP_API_URL}/v1/user/get-balance?userId=6339`,
{ {
headers: { headers: {
...constants.SCRAP_API_BASE_HEADERS, ...constants.SCRAP_API_BASE_HEADERS,
Authorization: jwt, Authorization: jwt,
"User-Agent": getRandomUserAgent(), "User-Agent": getRandomUserAgent(),
}, },
}, },
); );
if (res.status !== 200) { if (res.status !== 200) {
return false; return false;
}
const rj = (await res.json()) as {
code: number;
success: boolean;
message: string;
data: any;
time: string;
};
return rj.code == 200 && rj.success;
} catch (err) {
console.log(err);
return false;
} }
const rj = (await res.json()) as {
code: number;
success: boolean;
message: string;
data: any;
time: string;
};
return rj.code == 200 && rj.success;
} catch (err) {
console.log(err);
return false;
}
}; };
export const getSessionToken = async (payload: { export const getSessionToken = async (payload: {
userId: string; userId: string;
password: string; password: string;
verifyToken: string; verifyToken: string;
code: string; code: string;
userType: number; userType: number;
}): Promise<{ ok: boolean; message: string }> => { }): Promise<{ ok: boolean; message: string }> => {
console.log("Requesting..."); console.log("Requesting...");
const res = await fetch(`${constants.SCRAP_API_URL}/v1/auth/login`, { const res = await fetch(`${constants.SCRAP_API_URL}/v1/auth/login`, {
method: "POST", method: "POST",
headers: { headers: {
...constants.SCRAP_API_BASE_HEADERS, ...constants.SCRAP_API_BASE_HEADERS,
"User-Agent": getRandomUserAgent(), "User-Agent": getRandomUserAgent(),
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify(payload), body: JSON.stringify(payload),
}); });
const out = await res.json(); const out = await res.json();
if (out.code !== 200) { if (out.code !== 200) {
return { ok: false, message: out.message }; return { ok: false, message: out.message };
} }
return { ok: true, message: out.data.token }; return { ok: true, message: out.data.token };
}; };
export async function getUsersBalance(userId: number, jwt: string) { export async function getUsersBalance(userId: number, jwt: string) {
try { try {
const res = await fetch( const res = await fetch(
`${constants.SCRAP_API_URL}/v1/user/get-balance?userId=${userId}`, `${constants.SCRAP_API_URL}/v1/user/get-balance?userId=${userId}`,
{ {
headers: { headers: {
...constants.SCRAP_API_BASE_HEADERS, ...constants.SCRAP_API_BASE_HEADERS,
Authorization: jwt, Authorization: jwt,
"User-Agent": getRandomUserAgent(), "User-Agent": getRandomUserAgent(),
}, },
}, },
); );
const rj = (await res.json()) as { const rj = (await res.json()) as {
code: number; code: number;
success: boolean; success: boolean;
message: string; message: string;
data: { allowedBalance: number; balance: number }; data: { allowedBalance: number; balance: number };
time: string; time: string;
}; };
if (res.status !== 200 || rj.code !== 200 || !rj.success) { if (res.status !== 200 || rj.code !== 200 || !rj.success) {
console.log( console.log(
`[!] Error getting balance for ${userId} :: ${JSON.stringify(rj)}`, `[!] Error getting balance for ${userId} :: ${JSON.stringify(rj)}`,
); );
return false; return false;
}
return rj.data.balance;
} catch (err) {
console.log(err);
return false;
} }
return rj.data.balance;
} catch (err) {
console.log(err);
return false;
}
} }
export const getDealers = async (jwt: string, distributor_ids: string[]) => { export const getDealers = async (jwt: string, distributor_ids: string[]) => {
try { try {
// // Create an array of promises for each fetch request // // Create an array of promises for each fetch request
const requests = distributor_ids.map(async (did) => { const requests = distributor_ids.map(async (did) => {
await sleep(rng(100, 10000)); await sleep(rng(100, 10000));
const res = await fetch( const res = await fetch(
`${constants.SCRAP_API_URL}/v1/user/dealer-list`, `${constants.SCRAP_API_URL}/v1/user/dealer-list`,
{ {
method: "POST", method: "POST",
headers: { headers: {
...constants.SCRAP_API_BASE_HEADERS, ...constants.SCRAP_API_BASE_HEADERS,
"Content-Type": "application/json", "Content-Type": "application/json",
"User-Agent": getRandomUserAgent(), "User-Agent": getRandomUserAgent(),
Authorization: jwt, Authorization: jwt,
}, },
body: JSON.stringify({ body: JSON.stringify({
page: 1, page: 1,
pageSize: 999999, pageSize: 999999,
parentDistributor: parseInt(did), parentDistributor: parseInt(did),
}), }),
}, },
); );
const data = (await res.json()) as { const data = (await res.json()) as {
code: number; code: number;
success: boolean; success: boolean;
message: string; message: string;
data: { data: {
items: any[]; items: any[];
total: number; total: number;
}; };
}; };
if (data.code !== 200 || !data.success) { if (data.code !== 200 || !data.success) {
return {
dealers: [],
ok: false,
code: data.code,
message: data.message,
};
}
const dealers = data.data.items.map((item) => item.dealer);
// dumpDealers(dealers);
return {
dealers,
ok: res.status === 200 && data.success,
code: data.code,
message: data.message,
};
});
// // Wait for all promises to resolve
const responses = await Promise.all(requests);
const dealers: LooseApiUser[] = [];
const errors: { message: string }[] = [];
for (const res of responses) {
if (res.code !== 200 || !res.ok) {
errors.push({ message: res.message });
continue;
}
for (const dealer of res.dealers) {
dealers.push(dealer);
}
}
// fs.writeFileSync("dealers.json", JSON.stringify(dealers, null, 2));
return { dealers, errors };
} catch (err) {
console.error(err);
return { return {
dealers: [], dealers: [],
ok: false, errors: [{ message: "An error occured during fetching dealers" }],
code: data.code,
message: data.message,
}; };
}
const dealers = data.data.items.map((item) => item.dealer);
// dumpDealers(dealers);
return {
dealers,
ok: res.status === 200 && data.success,
code: data.code,
message: data.message,
};
});
// // Wait for all promises to resolve
const responses = await Promise.all(requests);
const dealers: LooseApiUser[] = [];
const errors: { message: string }[] = [];
for (const res of responses) {
if (res.code !== 200 || !res.ok) {
errors.push({ message: res.message });
continue;
}
for (const dealer of res.dealers) {
dealers.push(dealer);
}
} }
// fs.writeFileSync("dealers.json", JSON.stringify(dealers, null, 2));
return { dealers, errors };
} catch (err) {
console.error(err);
return {
dealers: [],
errors: [{ message: "An error occured during fetching dealers" }],
};
}
}; };
export const getDistributors = async (jwt: string) => { export const getDistributors = async (jwt: string) => {
const res = await fetch( const res = await fetch(
`${constants.SCRAP_API_URL}/v1/user/distributor-list`, `${constants.SCRAP_API_URL}/v1/user/distributor-list`,
{ {
method: "POST", method: "POST",
headers: { headers: {
...constants.SCRAP_API_BASE_HEADERS, ...constants.SCRAP_API_BASE_HEADERS,
Authorization: jwt, Authorization: jwt,
"Content-Type": "application/json", "Content-Type": "application/json",
"User-Agent": getRandomUserAgent(), "User-Agent": getRandomUserAgent(),
}, },
body: JSON.stringify({ body: JSON.stringify({
page: 1, page: 1,
pageSize: 999999, pageSize: 999999,
parentDistributor: 15, parentDistributor: 15,
}), }),
}, },
); );
const json = (await res.json()) as { const json = (await res.json()) as {
code: number; code: number;
success: boolean; success: boolean;
message: string; message: string;
data: { total: number; items: any[] }; data: { total: number; items: any[] };
}; };
if (!json.data.items || json.code !== 200 || !json.success) { if (!json.data.items || json.code !== 200 || !json.success) {
return { ok: false, message: json.message, data: [] }; return { ok: false, message: json.message, data: [] };
} }
// fs.writeFileSync( // fs.writeFileSync(
// "distributors.json", // "distributors.json",
// JSON.stringify(json.data.items, null, 2), // JSON.stringify(json.data.items, null, 2),
// ); // );
// dumpDistributors(json.data.items.map((item) => item.distributor)); // dumpDistributors(json.data.items.map((item) => item.distributor));
return { return {
ok: true, ok: true,
message: "", message: "",
data: json.data.items.map((item) => item.distributor), data: json.data.items.map((item) => item.distributor),
}; };
}; };
export const getDraws = async (jwt: string) => { export const getDraws = async (jwt: string) => {
const res = await fetch( const res = await fetch(
`${constants.SCRAP_API_URL}/v1/draw/list-my?userId=15`, `${constants.SCRAP_API_URL}/v1/draw/list-my?userId=15`,
{ {
method: "GET", method: "GET",
headers: { headers: {
...constants.SCRAP_API_BASE_HEADERS, ...constants.SCRAP_API_BASE_HEADERS,
Authorization: jwt, Authorization: jwt,
"Content-Type": "application/json", "Content-Type": "application/json",
"User-Agent": getRandomUserAgent(), "User-Agent": getRandomUserAgent(),
}, },
}, },
); );
type J = { type J = {
code: number; code: number;
success: boolean; success: boolean;
message: string; message: string;
data: { draw: Draw }[]; data: { draw: Draw }[];
}; };
let decoded = (await res.json()) as { data: J }; let decoded = (await res.json()) as { data: J };
const json = (decoded.data.success ? decoded.data : decoded) as any as J; const json = (decoded.data.success ? decoded.data : decoded) as any as J;
if (json.code !== 200 || !json.success || !json.data) { if (json.code !== 200 || !json.success || !json.data) {
return { ok: false, message: json.message, data: [] }; return { ok: false, message: json.message, data: [] };
} }
return { return {
ok: true, ok: true,
message: "", message: "",
data: json.data.map((item) => item.draw), data: json.data.map((item) => item.draw),
}; };
}; };
export const getData = async ( export const getData = async (
jwt: string, jwt: string,
userIds: number[], userIds: number[],
drawId: number, drawId: number,
chosenDate: string, chosenDate: string,
) => { ) => {
const res = await fetch(`${constants.SCRAP_API_URL}/v1/book/list2`, { const res = await fetch(`${constants.SCRAP_API_URL}/v1/book/list2`, {
method: "POST", method: "POST",
headers: { headers: {
...constants.SCRAP_API_BASE_HEADERS, ...constants.SCRAP_API_BASE_HEADERS,
Authorization: jwt, Authorization: jwt,
"Content-Type": "application/json", "Content-Type": "application/json",
"User-Agent": getRandomUserAgent(), "User-Agent": getRandomUserAgent(),
}, },
body: JSON.stringify({ body: JSON.stringify({
userType: 3, userType: 3,
userIds, userIds,
drawId: drawId, drawId: drawId,
startDate: chosenDate, startDate: chosenDate,
endDate: chosenDate, endDate: chosenDate,
beAdmin: false, beAdmin: false,
containImported: false, containImported: false,
keyword: "", keyword: "",
}), }),
}); });
type J = { type J = {
code: number; code: number;
success: boolean; success: boolean;
message: string; message: string;
data: { book: BookingEntry; user: any }[]; data: { book: BookingEntry; user: any }[];
}; };
let decoded = (await res.json()) as { data: J }; let decoded = (await res.json()) as { data: J };
const json = (decoded.data.success ? decoded.data : decoded) as any as J; const json = (decoded.data.success ? decoded.data : decoded) as any as J;
if (json.code !== 200 || !json.success || !json.data) { if (json.code !== 200 || !json.success || !json.data) {
return { ok: false, message: json.message, data: [] }; return { ok: false, message: json.message, data: [] };
} }
return { ok: true, message: "", data: json.data.map((e) => e.book) }; return { ok: true, message: "", data: json.data.map((e) => e.book) };
}; };
export const mockGetUserData = async ( export const mockGetUserData = async (
jwt: string, jwt: string,
userIds: number[], userIds: number[],
drawId: number, drawId: number,
chosenDate: string, chosenDate: string,
) => { ) => {
const entries = [] as BookingEntry[]; const entries = [] as BookingEntry[];
const rng = (min: number, max: number) => { const rng = (min: number, max: number) => {
return Math.floor(Math.random() * (max - min + 1)) + min; return Math.floor(Math.random() * (max - min + 1)) + min;
}; };
const randomCeil = rng(10_000, 200_000); const randomCeil = rng(10_000, 200_000);
await sleep(rng(100, 1000)); await sleep(rng(100, 1000));
for (let i = 0; i < randomCeil; i++) { for (let i = 0; i < randomCeil; i++) {
const _f = rng(5, 50); const _f = rng(5, 50);
const _s = rng(5, 50); const _s = rng(5, 50);
const f = _f - (_f % 5); const f = _f - (_f % 5);
const s = _s - (_s % 5); const s = _s - (_s % 5);
entries.push({ entries.push({
id: getULID(), id: getULID(),
bookDate: chosenDate, bookDate: chosenDate,
changedBalance: f + s, changedBalance: f + s,
first: f, first: f,
second: s, second: s,
dealerId: userIds[rng(0, userIds.length - 1)], dealerId: userIds[rng(0, userIds.length - 1)],
distributorId: 6339, distributorId: 6339,
drawId: drawId, drawId: drawId,
number: rng(0, 9999).toString(), number: rng(0, 9999).toString(),
requestId: new Date().getTime().toString(), requestId: new Date().getTime().toString(),
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
sheetId: "0", sheetId: "0",
sheetName: "", sheetName: "",
}); });
} }
return { ok: true, message: "", data: entries }; return { ok: true, message: "", data: entries };
}; };

View File

@@ -1,320 +1,334 @@
import { getRandomUserAgent, getULID, sleep } from "$lib/utils"; import { getRandomUserAgent, getULID, sleep } from "$lib/utils";
import { constants } from "$lib/utils/constants"; import { constants } from "$lib/utils/constants";
import type { import type {
ApiPostUserWithParent, ApiPostUserWithParent,
APISession, APISession,
Draw, Draw,
PostDataEntry, PostDataEntry,
ServerError, ServerError,
} from "$lib/utils/data.types"; } from "$lib/utils/data.types";
import Fetch from "node-fetch"; import Fetch from "node-fetch";
import { HttpsProxyAgent } from "https-proxy-agent"; import { HttpsProxyAgent } from "https-proxy-agent";
export type APIRespnose<T> = { export type APIRespnose<T> = {
code: number; code: number;
success: boolean; success: boolean;
message: string; message: string;
data: T; data: T;
time: string; time: string;
}; };
export function buildMessageString( export function buildMessageString(
ptr: number, ptr: number,
rows: PostDataEntry[], rows: PostDataEntry[],
distributorId: number, distributorId: number,
dealerId: number, dealerId: number,
drawId: number, drawId: number,
date: string, date: string,
) { ) {
let message = ""; let message = "";
let jumpSize = Math.floor(Math.random() * 490) + 10; let jumpSize = Math.floor(Math.random() * 490) + 10;
let total = 0; let total = 0;
let startReqId = new Date().getTime(); let startReqId = new Date().getTime();
let x = 0; let x = 0;
for (let j = ptr; j < ptr + jumpSize; j++) { for (let j = ptr; j < ptr + jumpSize; j++) {
if (j >= rows.length) { if (j >= rows.length) {
break; break;
}
const row = rows[j];
const reqId = startReqId + x++;
const no = row.number.trim();
const f = row.first;
const s = row.second;
const mTotal = f + s;
if (mTotal <= 0) {
continue;
}
total += mTotal;
message += `${reqId},${distributorId},${dealerId},${drawId},${date},${no},${f},${s},${mTotal};`;
} }
const row = rows[j]; message = message.slice(0, -1);
const reqId = startReqId + x++; return { message, total, jumped: ptr + jumpSize };
const no = row.number.trim();
const f = row.first;
const s = row.second;
const mTotal = f + s;
if (mTotal <= 0) {
continue;
}
total += mTotal;
message += `${reqId},${distributorId},${dealerId},${drawId},${date},${no},${f},${s},${mTotal};`;
}
message = message.slice(0, -1);
return { message, total, jumped: ptr + jumpSize };
} }
export async function postDataToApi(payload: { export async function postDataToApi(payload: {
sessions: Record<string, APISession>; sessions: Record<string, APISession>;
draw: Draw; draw: Draw;
data: PostDataEntry[]; data: PostDataEntry[];
users: ApiPostUserWithParent[]; users: ApiPostUserWithParent[];
}) { }) {
const responses = [] as APIRespnose<[]>[]; const responses = [] as APIRespnose<[]>[];
const responsesIds = [] as { requestId: number; bookId: string }[]; const responsesIds = [] as { requestId: number; bookId: string }[];
let failedResponses = 0; let failedResponses = 0;
let successResponses = 0; let successResponses = 0;
console.log(`[+] Sending ${payload.data.length} requests...`); console.log(`[+] Sending ${payload.data.length} requests...`);
const dataByUser = {} as Record<string, PostDataEntry[]>; const dataByUser = {} as Record<string, PostDataEntry[]>;
for (const row of payload.data) { for (const row of payload.data) {
const userId = row.userId ?? ""; const userId = row.userId ?? "";
if (userId.length < 1) { if (userId.length < 1) {
console.log(`[!] User not found for request ${row.userId}`); console.log(`[!] User not found for request ${row.userId}`);
return { return {
ok: false, ok: false,
detail: "User not found to post data with", detail: "User not found to post data with",
errors: [{ message: "User not found for request" }] as ServerError, errors: [
}; { message: "User not found for request" },
] as ServerError,
};
}
if (!dataByUser[userId]) {
dataByUser[userId] = [];
}
dataByUser[userId].push(row);
} }
if (!dataByUser[userId]) {
dataByUser[userId] = [];
}
dataByUser[userId].push(row);
}
try { try {
const userPromises = Object.entries(dataByUser).map( const userPromises = Object.entries(dataByUser).map(
async ([userId, userData]) => { async ([userId, userData]) => {
const session = payload.sessions[userId]; const session = payload.sessions[userId];
const usr = payload.users.find((u) => u.userId === userId); const usr = payload.users.find((u) => u.userId === userId);
if (!usr) { if (!usr) {
throw new Error(`User ${userId} not found for posting to api`); throw new Error(
`User ${userId} not found for posting to api`,
);
}
const distId = usr.parentDistributor ?? 0;
const dealerId = Number(session.userId.split(":")[1]);
const drawId = Number(payload.draw.id.split(":")[1]);
const date = new Date().toISOString().split("T")[0];
let ptr = 0;
const userResponseIds = [] as {
requestId: number;
bookId: string;
}[];
while (ptr < userData.length) {
let tries = 0;
while (tries < 3) {
let { message, total, jumped } = buildMessageString(
ptr,
userData,
distId,
dealerId,
drawId,
date,
);
const res = await mockSendBatchRequest(
session,
dealerId,
payload.draw,
total,
message,
);
let rj:
| APIRespnose<{
bookDtos: {
bookId: string;
requestId: number;
}[];
}>
| undefined = undefined;
try {
rj = (await res.json()) as any;
} catch (err) {
console.log(
"Encountered error while parsing post response",
);
console.log(res.status, err);
}
if (rj && rj.code === 200 && res.status === 200) {
ptr = jumped;
userResponseIds.push(
...rj.data.bookDtos.map((b) => ({
requestId: b.requestId as number,
bookId: b.bookId as string,
})),
);
successResponses++;
break;
}
console.log("Failed to send send post request");
console.log(res.status, rj);
failedResponses++;
tries++;
}
if (tries >= 3) {
if (userResponseIds.length > 0) {
const out = await deleteAllBookedEntries({
data: userResponseIds,
closeTime: payload.draw.closeTime,
dealerId,
drawId,
session,
});
console.log(await out.text());
}
throw new Error(
`Failed to send data to api for user ${userId}`,
);
}
}
return userResponseIds;
},
);
// Wait for all user processes to complete
const results = await Promise.allSettled(userPromises);
// Process results
let hasErrors = false;
results.forEach((result) => {
if (result.status === "fulfilled") {
responsesIds.push(...result.value);
} else {
hasErrors = true;
console.log(`[!] Error processing user`);
console.log(result.reason);
}
});
if (hasErrors) {
return {
ok: false,
detail: "Failed to post data to API for some users",
errors: [
{ message: "Failed to post data to API for some users" },
] as ServerError,
};
} }
const distId = usr.parentDistributor ?? 0; console.log(`[+] Finished sending ${payload.data.length} requests`);
const dealerId = Number(session.userId.split(":")[1]); console.log(`[?] Failed responses: ${failedResponses}`);
const drawId = Number(payload.draw.id.split(":")[1]); console.log(`[?] Success responses: ${successResponses}`);
const date = new Date().toISOString().split("T")[0]; return {
ok: true,
let ptr = 0; detail: "Successfully sent data to api",
const userResponseIds = [] as { requestId: number; bookId: string }[]; data: responses,
};
while (ptr < userData.length) { } catch (err) {
let tries = 0; console.log(err);
while (tries < 3) { return {
let { message, total, jumped } = buildMessageString( ok: false,
ptr, detail: "Failed to send data to api",
userData, };
distId,
dealerId,
drawId,
date,
);
const res = await sendBatchRequest(
session,
dealerId,
payload.draw,
total,
message,
);
let rj:
| APIRespnose<{
bookDtos: { bookId: string; requestId: number }[];
}>
| undefined = undefined;
try {
rj = (await res.json()) as any;
} catch (err) {
console.log("Encountered error while parsing post response");
console.log(res.status, err);
}
if (rj && rj.code === 200 && res.status === 200) {
ptr = jumped;
userResponseIds.push(
...rj.data.bookDtos.map((b) => ({
requestId: b.requestId as number,
bookId: b.bookId as string,
})),
);
successResponses++;
break;
}
console.log("Failed to send send post request");
console.log(res.status, rj);
failedResponses++;
tries++;
}
if (tries >= 3) {
if (userResponseIds.length > 0) {
const out = await deleteAllBookedEntries({
data: userResponseIds,
closeTime: payload.draw.closeTime,
dealerId,
drawId,
session,
});
console.log(await out.text());
}
throw new Error(`Failed to send data to api for user ${userId}`);
}
}
return userResponseIds;
},
);
// Wait for all user processes to complete
const results = await Promise.allSettled(userPromises);
// Process results
let hasErrors = false;
results.forEach((result) => {
if (result.status === "fulfilled") {
responsesIds.push(...result.value);
} else {
hasErrors = true;
console.log(`[!] Error processing user`);
console.log(result.reason);
}
});
if (hasErrors) {
return {
ok: false,
detail: "Failed to post data to API for some users",
errors: [
{ message: "Failed to post data to API for some users" },
] as ServerError,
};
} }
console.log(`[+] Finished sending ${payload.data.length} requests`);
console.log(`[?] Failed responses: ${failedResponses}`);
console.log(`[?] Success responses: ${successResponses}`);
return {
ok: true,
detail: "Successfully sent data to api",
data: responses,
};
} catch (err) {
console.log(err);
return {
ok: false,
detail: "Failed to send data to api",
};
}
} }
async function sendBatchRequest( async function sendBatchRequest(
session: APISession, session: APISession,
dealerId: number, dealerId: number,
draw: Draw, draw: Draw,
changedBalance: number, changedBalance: number,
body: string, body: string,
) { ) {
return Fetch(`${constants.SCRAP_API_URL}/v1/book/add-multiple`, { return Fetch(`${constants.SCRAP_API_URL}/v1/book/add-multiple`, {
agent: new HttpsProxyAgent(`http://${session.ip}`), agent: new HttpsProxyAgent(`http://${session.ip}`),
method: "POST", method: "POST",
headers: { headers: {
...constants.SCRAP_API_BASE_HEADERS, ...constants.SCRAP_API_BASE_HEADERS,
"Content-Type": "application/json;charset=UTF-8", "Content-Type": "application/json;charset=UTF-8",
Authorization: session.sessionToken, Authorization: session.sessionToken,
"User-Agent": getRandomUserAgent(), "User-Agent": getRandomUserAgent(),
}, },
body: JSON.stringify({ body: JSON.stringify({
dealerId, dealerId,
drawId: Number(draw.id.split(":")[1]), drawId: Number(draw.id.split(":")[1]),
closeTime: draw.closeTime, closeTime: draw.closeTime,
date: new Date().toISOString().split("T")[0], date: new Date().toISOString().split("T")[0],
changedBalance, changedBalance,
insertData: body, insertData: body,
}), }),
}); });
} }
async function mockSendBatchRequest( async function mockSendBatchRequest(
session: APISession, session: APISession,
dealerId: number, dealerId: number,
draw: Draw, draw: Draw,
changedBalance: number, changedBalance: number,
body: string, body: string,
) { ) {
console.log("----- Sending batch request ------"); console.log("----- Sending batch request ------");
console.log(session); console.log(session);
console.log(dealerId); console.log(dealerId);
console.log(draw); console.log(draw);
console.log(changedBalance); console.log(changedBalance);
console.log(body); console.log(body);
console.log("----------------------------------"); console.log("----------------------------------");
// between 5 to 20 ms // between 5 to 20 ms
await sleep(Math.floor(Math.random() * 1000) + 50); await sleep(Math.floor(Math.random() * 1000) + 50);
// if (Math.random() < 0.005) { // if (Math.random() < 0.005) {
// return new Response( // return new Response(
// JSON.stringify({ // JSON.stringify({
// code: 500, // code: 500,
// success: false, // success: false,
// message: "Failed", // message: "Failed",
// data: {}, // data: {},
// time: new Date().toISOString(), // time: new Date().toISOString(),
// }), // }),
// { // {
// status: 500, // status: 500,
// headers: { "Content-Type": "application/json" }, // headers: { "Content-Type": "application/json" },
// statusText: "Failed", // statusText: "Failed",
// }, // },
// ); // );
// } // }
return new Response( return new Response(
JSON.stringify({ JSON.stringify({
code: 200, code: 200,
success: true, success: true,
message: "Success", message: "Success",
data: { data: {
bookDtos: body.split(";").map((e) => { bookDtos: body.split(";").map((e) => {
return { return {
bookId: getULID(), bookId: getULID(),
requestId: +e.split(",")[0], requestId: +e.split(",")[0],
}; };
}),
},
time: new Date().toISOString(),
}), }),
}, {
time: new Date().toISOString(), status: 200,
}), headers: { "Content-Type": "application/json" },
{ statusText: "OK",
status: 200, },
headers: { "Content-Type": "application/json" }, );
statusText: "OK",
},
);
} }
async function deleteAllBookedEntries({ async function deleteAllBookedEntries({
session, session,
data, data,
dealerId, dealerId,
drawId, drawId,
closeTime, closeTime,
}: { }: {
session: APISession; session: APISession;
data: { bookId: string; requestId: number }[]; data: { bookId: string; requestId: number }[];
dealerId: number; dealerId: number;
drawId: number; drawId: number;
closeTime: string; closeTime: string;
}) { }) {
return Fetch(`${constants.SCRAP_API_URL}/v1/book/delete-multiple`, { return Fetch(`${constants.SCRAP_API_URL}/v1/book/delete-multiple`, {
agent: new HttpsProxyAgent(`http://${session.ip}`), agent: new HttpsProxyAgent(`http://${session.ip}`),
method: "POST", method: "POST",
headers: { headers: {
...constants.SCRAP_API_BASE_HEADERS, ...constants.SCRAP_API_BASE_HEADERS,
"Content-Type": "application/json;charset=UTF-8", "Content-Type": "application/json;charset=UTF-8",
Authorization: session.sessionToken, Authorization: session.sessionToken,
"User-Agent": getRandomUserAgent(), "User-Agent": getRandomUserAgent(),
}, },
body: JSON.stringify({ body: JSON.stringify({
bookIds: data.map((e) => e.bookId), bookIds: data.map((e) => e.bookId),
closeTime, closeTime,
dealerId, dealerId,
drawId, drawId,
}), }),
}); });
} }
// export async function postDataToApi(payload: { // export async function postDataToApi(payload: {

View File

@@ -2,446 +2,462 @@ import { dbApiPostData } from "$lib/server/db/apipostdata.db";
import { dbApiUser } from "$lib/server/db/apiuser.db"; import { dbApiUser } from "$lib/server/db/apiuser.db";
import { getReducedFinalSheet } from "$lib/server/finalsheet.helpers"; import { getReducedFinalSheet } from "$lib/server/finalsheet.helpers";
import { import {
adjustRatesIfDuplicatesFound, adjustRatesIfDuplicatesFound,
pairRatesWithNumbers, pairRatesWithNumbers,
removeNumbersWithRepeatingDigits, removeNumbersWithRepeatingDigits,
splitRatesIntoSmallerForRowsWithLargerRates, splitRatesIntoSmallerForRowsWithLargerRates,
spreadRatesForNumbersBetweenUsers, spreadRatesForNumbersBetweenUsers,
} from "$lib/server/postdata/postdata.gen.helpers"; } from "$lib/server/postdata/postdata.gen.helpers";
import { getAllSessions } from "$lib/server/utils/session.service"; import { getAllSessions } from "$lib/server/utils/session.service";
import { getDefaultTotals, getULID } from "$lib/utils"; import { getDefaultTotals, getULID } from "$lib/utils";
import type { import type {
ApiPostUser, ApiPostUser,
ApiPostUserWithParent, ApiPostUserWithParent,
PresetDataEntry, PresetDataEntry,
PostDataEntry, PostDataEntry,
PostDataFilters, PostDataFilters,
PostDataHistoryFilters, PostDataHistoryFilters,
ReducedFinalSheetData, ReducedFinalSheetData,
ReducedFinalSheetRow, ReducedFinalSheetRow,
ServerError, ServerError,
} from "$lib/utils/data.types"; } from "$lib/utils/data.types";
import { dbPresetData } from "$lib/server/db/presetdata.db"; import { dbPresetData } from "$lib/server/db/presetdata.db";
import { getUsersBalance } from "$lib/server/external/api.scraping.helpers"; import { getUsersBalance } from "$lib/server/external/api.scraping.helpers";
function filterMatching( function filterMatching(
data: ReducedFinalSheetRow[], data: ReducedFinalSheetRow[],
min: number, min: number,
max: number, max: number,
sheetType: "first" | "second", sheetType: "first" | "second",
) { ) {
let abNums = new Set<string>(); let abNums = new Set<string>();
let abcNums = new Set<string>(); let abcNums = new Set<string>();
for (const row of data) { for (const row of data) {
if (row.prize[sheetType] >= min && row.prize[sheetType] <= max) { if (row.prize[sheetType] >= min && row.prize[sheetType] <= max) {
abNums.add(`${row.number[0]}${row.number[1]}`); abNums.add(`${row.number[0]}${row.number[1]}`);
abcNums.add(`${row.number[0]}${row.number[1]}${row.number[2]}`); abcNums.add(`${row.number[0]}${row.number[1]}${row.number[2]}`);
}
} }
} return { abNums, abcNums };
return { abNums, abcNums };
} }
export async function updateBalanceOfPostUsers(users: ApiPostUserWithParent[]) { export async function updateBalanceOfPostUsers(users: ApiPostUserWithParent[]) {
const sessions = await getAllSessions(); const sessions = await getAllSessions();
const balances = [] as { id: string; balance: number }[]; console.log(sessions);
for (const user of users) { console.log(`Fetching balances`);
const session = sessions.find((e) => e.value.userId === user.id); const balances = [] as { id: string; balance: number }[];
const jwt = session?.value.sessionToken; for (const user of users) {
if (!jwt) { console.log(`Finding ${user.id} in sessions`);
return { const session = sessions.find((e) => e.value.userId.includes(user.id));
ok: false, const jwt = session?.value.sessionToken;
detail: `Session not found for user ${user.userId}`, if (!jwt) {
}; return {
ok: false,
detail: `Session not found for user ${user.userId}`,
};
}
const uid = session.value.userId.toString();
console.log(`Found ${uid} in session`);
const out = await getUsersBalance(+uid.split(":")[1], jwt);
if (!out) {
return {
ok: false,
detail: `Error fetching balance for user ${user.userName}`,
};
}
balances.push({ id: uid, balance: out });
} }
const out = await getUsersBalance(+user.id.split(":")[1], jwt); console.log(`Updating balances`);
if (!out) { console.log(balances);
return { await dbApiUser.updatePostUsersBalances(balances);
ok: false, return {
detail: `Error fetching balance for user ${user.userName}`, ok: true,
}; detail: "",
} data: users.map((u) => {
balances.push({ id: user.id, balance: out }); const bal = balances.find((b) => b.id === u.id);
} if (!bal) {
await dbApiUser.updatePostUsersBalances(balances); console.log(`ERROR: Balance not found for user ${u.userName}`);
return { }
ok: true, return { ...u, balance: bal?.balance ?? 0 };
detail: "", }),
data: users.map((u) => { };
const bal = balances.find((b) => b.id === u.id);
if (!bal) {
console.log(`ERROR: Balance not found for user ${u.userName}`);
}
return { ...u, balance: bal?.balance ?? 0 };
}),
};
} }
export async function fetchDataForPosting( export async function fetchDataForPosting(
date: string, date: string,
input: PostDataFilters, input: PostDataFilters,
users: ApiPostUser[], users: ApiPostUser[],
) { ) {
console.log(`The input ${JSON.stringify(input, null, 2)}`); console.log(`The input ${JSON.stringify(input, null, 2)}`);
const { minPrize, maxPrize } = input; const { minPrize, maxPrize } = input;
const draw = input.draw!; const draw = input.draw!;
const fsData = { const fsData = {
id: getULID(), id: getULID(),
date, date,
drawId: draw.id, drawId: draw.id,
data: [],
totals: getDefaultTotals(),
} as ReducedFinalSheetData;
if (!draw) {
return {
ok: false,
detail: `Draw for the passed draw ID not found`,
data: [],
users: [],
errors: [
{ message: `Draw for the passed draw ID not found` },
] as ServerError,
};
}
const data = await getReducedFinalSheet(fsData);
if (!data.ok) {
return {
ok: false,
detail: `Error compiling final sheet`,
data: [],
users: [],
errors: data.errors,
};
}
console.log("[+] Filtering the fs data to get the numbers");
const filteredF = filterMatching(fsData.data, minPrize, maxPrize, "first");
console.log(
`Filtered data: ${filteredF.abNums.size}; ${filteredF.abcNums.size}`,
);
// ------------------------------------------
let _abNums = new Set<string>(),
_abcNums = new Set<string>();
for (const each of filteredF.abNums) _abNums.add(each);
for (const each of filteredF.abcNums) _abcNums.add(each);
let abNums = Array.from(_abNums),
abcNums = Array.from(_abcNums);
if (draw.filterDuplicatesWhilePosting === true) {
console.log(`[+] Removing numbers that have repeating digits`);
console.log(`[=] Original : AB: ${abNums.length}, ABC: ${abcNums.length}`);
abNums = removeNumbersWithRepeatingDigits(abNums);
abcNums = removeNumbersWithRepeatingDigits(abcNums);
}
console.log(`[=] AB: ${abNums.length}, ABC: ${abcNums.length}`);
console.log(`Fetching preset data`);
const presetData = await dbPresetData.getDataGroupedBySheetByDraw(
date,
+draw.id.split(":")[1],
);
console.log(`${presetData.all.length} preset entries found`);
for (let tries = 0; tries < 3; tries++) {
console.log(`[✍️] Try ${tries + 1} of generating the result`);
const out = await generatePostDataArrayFromBaseInfo(
input,
users,
abNums,
abcNums,
presetData,
);
if (out.ok) {
return out;
}
if (out.detail.includes("Not enough balance")) {
return {
ok: false,
detail: `Users don't have enough balance to post the data, try reducing the rates`,
data: [], data: [],
users: [], totals: getDefaultTotals(),
}; } as ReducedFinalSheetData;
if (!draw) {
return {
ok: false,
detail: `Draw for the passed draw ID not found`,
data: [],
users: [],
errors: [
{ message: `Draw for the passed draw ID not found` },
] as ServerError,
};
}
const data = await getReducedFinalSheet(fsData);
if (!data.ok) {
return {
ok: false,
detail: `Error compiling final sheet`,
data: [],
users: [],
errors: data.errors,
};
} }
}
return { console.log("[+] Filtering the fs data to get the numbers");
ok: false, const filteredF = filterMatching(fsData.data, minPrize, maxPrize, "first");
detail: `Could not generate data, please try adjusting the filters`, console.log(
data: [], `Filtered data: ${filteredF.abNums.size}; ${filteredF.abcNums.size}`,
}; );
// ------------------------------------------
let _abNums = new Set<string>(),
_abcNums = new Set<string>();
for (const each of filteredF.abNums) _abNums.add(each);
for (const each of filteredF.abcNums) _abcNums.add(each);
let abNums = Array.from(_abNums),
abcNums = Array.from(_abcNums);
if (draw.filterDuplicatesWhilePosting === true) {
console.log(`[+] Removing numbers that have repeating digits`);
console.log(
`[=] Original : AB: ${abNums.length}, ABC: ${abcNums.length}`,
);
abNums = removeNumbersWithRepeatingDigits(abNums);
abcNums = removeNumbersWithRepeatingDigits(abcNums);
}
console.log(`[=] AB: ${abNums.length}, ABC: ${abcNums.length}`);
console.log(`Fetching preset data`);
const presetData = await dbPresetData.getDataGroupedBySheetByDraw(
date,
+draw.id.split(":")[1],
);
console.log(`${presetData.all.length} preset entries found`);
for (let tries = 0; tries < 3; tries++) {
console.log(`[✍️] Try ${tries + 1} of generating the result`);
const out = await generatePostDataArrayFromBaseInfo(
input,
users,
abNums,
abcNums,
presetData,
);
if (out.ok) {
return out;
}
if (out.detail.includes("Not enough balance")) {
return {
ok: false,
detail: `Users don't have enough balance to post the data, try reducing the rates`,
data: [],
users: [],
};
}
}
return {
ok: false,
detail: `Could not generate data, please try adjusting the filters`,
data: [],
};
} }
export async function generatePostDataArrayFromBaseInfo( export async function generatePostDataArrayFromBaseInfo(
input: PostDataFilters, input: PostDataFilters,
users: ApiPostUser[], users: ApiPostUser[],
abNums: string[], abNums: string[],
abcNums: string[], abcNums: string[],
presetData: { presetData: {
all: PostDataEntry[]; all: PostDataEntry[];
abData: PresetDataEntry[]; abData: PresetDataEntry[];
abcData: PresetDataEntry[]; abcData: PresetDataEntry[];
}, },
) { ) {
console.log("[+] Spreading the rates for the numbers for all post user"); console.log("[+] Spreading the rates for the numbers for all post user");
const abData = splitRatesIntoSmallerForRowsWithLargerRates( const abData = splitRatesIntoSmallerForRowsWithLargerRates(
spreadRatesForNumbersBetweenUsers( spreadRatesForNumbersBetweenUsers(
adjustRatesIfDuplicatesFound( adjustRatesIfDuplicatesFound(
pairRatesWithNumbers(abNums, input.twoDigitRates), pairRatesWithNumbers(abNums, input.twoDigitRates),
presetData.abData, presetData.abData,
), ),
users.map((u) => u.userId), users.map((u) => u.userId),
), ),
); );
const abcData = splitRatesIntoSmallerForRowsWithLargerRates( const abcData = splitRatesIntoSmallerForRowsWithLargerRates(
spreadRatesForNumbersBetweenUsers( spreadRatesForNumbersBetweenUsers(
adjustRatesIfDuplicatesFound( adjustRatesIfDuplicatesFound(
pairRatesWithNumbers(abcNums, input.threeDigitRates), pairRatesWithNumbers(abcNums, input.threeDigitRates),
presetData.abcData, presetData.abcData,
), ),
users.map((u) => u.userId), users.map((u) => u.userId),
), ),
);
// ------------------------------------------
console.log(`[+] Adding ${abData.length} ab entries to final list`);
console.log(`[+] Adding ${abcData.length} abc entries to final list`);
const result = [] as PostDataEntry[];
const alreadyPresent = new Set<string>();
for (const each of abData) {
alreadyPresent.add(each.number);
result.push(each);
}
for (const each of abcData) {
alreadyPresent.add(each.number);
result.push(each);
}
// ------------------------------------------
const balanceCounts = {} as Record<string, number>;
for (const each of result) {
const uid = each.userId ?? "";
if (balanceCounts[uid] === undefined) {
balanceCounts[uid] = 0;
}
balanceCounts[uid] += each.first + each.second;
}
// ------------------------------------------
console.log(
`[+] Appending up to ${presetData.all.length} entries that are not ab, abc`,
);
for (const entry of presetData.all) {
if (
alreadyPresent.has(entry.number) ||
(entry.first < 5 && entry.second < 5)
) {
continue;
}
const randomUserId = users[Math.floor(Math.random() * users.length)].userId;
if (balanceCounts[randomUserId] === undefined) {
balanceCounts[randomUserId] = 0;
}
balanceCounts[randomUserId] += entry.first + entry.second;
result.push({ ...entry, userId: randomUserId });
}
// ------------------------------------------
const usersTotalbalance = users.reduce((a, b) => a + (b.balance ?? 0), 0);
let totalAmtForPostingData = Object.values(balanceCounts).reduce(
(acc, curr) => acc + curr,
0,
);
if (usersTotalbalance < totalAmtForPostingData) {
return {
ok: false,
detail: `Not enough balance to book overall with ${usersTotalbalance} < ${totalAmtForPostingData}`,
data: [],
users: [],
errors: [
{ message: `Not enough balance to book overall` },
] as ServerError,
};
}
function isDistributionUnbalanced() {
let out = false;
for (const key in balanceCounts) {
if (
balanceCounts[key] > (users.find((u) => u.userId === key)?.balance ?? 0)
) {
out = true;
break;
}
}
return out;
}
for (let tries = 0; tries < 5; tries++) {
console.log(
`Balance counts start : ${JSON.stringify(balanceCounts, null, 2)}`,
); );
rebalancePostDataListByBalanceOfUsers(balanceCounts, users, result); // ------------------------------------------
console.log(`Balance counts final : ${JSON.stringify(balanceCounts)}`); console.log(`[+] Adding ${abData.length} ab entries to final list`);
console.log(`[+] Adding ${abcData.length} abc entries to final list`);
let totalAmtForPostingDataAfterRebalance = Object.values( const result = [] as PostDataEntry[];
balanceCounts, const alreadyPresent = new Set<string>();
).reduce((acc, curr) => acc + curr, 0); for (const each of abData) {
alreadyPresent.add(each.number);
result.push(each);
}
for (const each of abcData) {
alreadyPresent.add(each.number);
result.push(each);
}
// ------------------------------------------
const balanceCounts = {} as Record<string, number>;
for (const each of result) {
const uid = each.userId ?? "";
if (balanceCounts[uid] === undefined) {
balanceCounts[uid] = 0;
}
balanceCounts[uid] += each.first + each.second;
}
// ------------------------------------------
console.log( console.log(
`Total amount for posting data after rebalance: ${totalAmtForPostingDataAfterRebalance}`, `[+] Appending up to ${presetData.all.length} entries that are not ab, abc`,
`Total balance of users: ${JSON.stringify(users.map((u) => ({ un: u.userName, b: u.balance })))}`,
); );
for (const entry of presetData.all) {
if (!isDistributionUnbalanced()) { if (
console.log(`[+] Distribution is balanced`); alreadyPresent.has(entry.number) ||
break; (entry.first < 5 && entry.second < 5)
) {
continue;
}
const randomUserId =
users[Math.floor(Math.random() * users.length)].userId;
if (balanceCounts[randomUserId] === undefined) {
balanceCounts[randomUserId] = 0;
}
balanceCounts[randomUserId] += entry.first + entry.second;
result.push({ ...entry, userId: randomUserId });
} }
console.log(`[!] Rebalancing again`);
}
if (isDistributionUnbalanced()) { // ------------------------------------------
const usersTotalbalance = users.reduce((a, b) => a + (b.balance ?? 0), 0);
let totalAmtForPostingData = Object.values(balanceCounts).reduce(
(acc, curr) => acc + curr,
0,
);
if (usersTotalbalance < totalAmtForPostingData) {
return {
ok: false,
detail: `Not enough balance to book overall with ${usersTotalbalance} < ${totalAmtForPostingData}`,
data: [],
users: [],
errors: [
{ message: `Not enough balance to book overall` },
] as ServerError,
};
}
function isDistributionUnbalanced() {
let out = false;
for (const key in balanceCounts) {
if (
balanceCounts[key] >
(users.find((u) => u.userId === key)?.balance ?? 0)
) {
out = true;
break;
}
}
return out;
}
for (let tries = 0; tries < 5; tries++) {
console.log(
`Balance counts start : ${JSON.stringify(balanceCounts, null, 2)}`,
);
rebalancePostDataListByBalanceOfUsers(balanceCounts, users, result);
console.log(`Balance counts final : ${JSON.stringify(balanceCounts)}`);
let totalAmtForPostingDataAfterRebalance = Object.values(
balanceCounts,
).reduce((acc, curr) => acc + curr, 0);
console.log(
`Total amount for posting data after rebalance: ${totalAmtForPostingDataAfterRebalance}`,
`Total balance of users: ${JSON.stringify(users.map((u) => ({ un: u.userName, b: u.balance })))}`,
);
if (!isDistributionUnbalanced()) {
console.log(`[+] Distribution is balanced`);
break;
}
console.log(`[!] Rebalancing again`);
}
if (isDistributionUnbalanced()) {
return {
ok: false,
detail: `Please regenerate dataset as the some users have not enough balance to book their entries`,
data: [],
users: [],
};
}
// ------------------------------------------
console.log(`[+] Shuffling ${result.length} entries for posting`);
shuffleArray(result);
return { return {
ok: false, ok: true,
detail: `Please regenerate dataset as the some users have not enough balance to book their entries`, detail: `Fetched the data successfully`,
data: [], data: result,
users: [], users,
errors: undefined,
}; };
}
// ------------------------------------------
console.log(`[+] Shuffling ${result.length} entries for posting`);
shuffleArray(result);
return {
ok: true,
detail: `Fetched the data successfully`,
data: result,
users,
errors: undefined,
};
} }
function shuffleArray<T>(array: T[]): T[] { function shuffleArray<T>(array: T[]): T[] {
for (let i = array.length - 1; i > 0; i--) { for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1)); const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]]; [array[i], array[j]] = [array[j], array[i]];
} }
return array; return array;
} }
export function rebalancePostDataListByBalanceOfUsers( export function rebalancePostDataListByBalanceOfUsers(
balanceCounts: Record<string, number>, balanceCounts: Record<string, number>,
users: ApiPostUser[], users: ApiPostUser[],
result: PostDataEntry[], result: PostDataEntry[],
) { ) {
console.log(
`[+] Checking if the users have enough balance to book their assigned data`,
);
for (const user of users) {
const usersBalance = user.balance ?? 0;
const dueForUser = balanceCounts[user.userId] ?? 0;
if (usersBalance === 0) {
console.log(`\n[!] ${user.userName} has no balance\n`);
continue;
}
if (usersBalance >= dueForUser) {
console.log(
`[✅] ${user.userName} can book the data of ${usersBalance} > ${dueForUser} `,
);
continue;
}
console.log( console.log(
`[!❎!] ${user.userName} can't book it all ${usersBalance} < ${dueForUser}`, `[+] Checking if the users have enough balance to book their assigned data`,
); );
const difference = dueForUser - usersBalance; for (const user of users) {
let differenceLeft = Number(difference); // make a copy const usersBalance = user.balance ?? 0;
const entriesToMove = result const dueForUser = balanceCounts[user.userId] ?? 0;
.filter((r) => { if (usersBalance === 0) {
if (r.userId === user.userId && differenceLeft > 0) { console.log(`\n[!] ${user.userName} has no balance\n`);
differenceLeft -= r.first + r.second; continue;
return true;
} }
}) if (usersBalance >= dueForUser) {
.map((r) => r.id); console.log(
console.log(`Have to move ${entriesToMove.length} entries to other users`); `[✅] ${user.userName} can book the data of ${usersBalance} > ${dueForUser} `,
);
continue;
}
console.log(
`[!❎!] ${user.userName} can't book it all ${usersBalance} < ${dueForUser}`,
);
// find a user who has enough balance const difference = dueForUser - usersBalance;
let differenceLeft = Number(difference); // make a copy
const entriesToMove = result
.filter((r) => {
if (r.userId === user.userId && differenceLeft > 0) {
differenceLeft -= r.first + r.second;
return true;
}
})
.map((r) => r.id);
console.log(
`Have to move ${entriesToMove.length} entries to other users`,
);
const userWithEnoughBalance = users.find((u) => { // find a user who has enough balance
return (
(u.balance ?? 0) - balanceCounts[u.userId] >= difference && const userWithEnoughBalance = users.find((u) => {
u.userId !== user.userId return (
); (u.balance ?? 0) - balanceCounts[u.userId] >= difference &&
}); u.userId !== user.userId
if (!userWithEnoughBalance) { );
return { });
ok: false, if (!userWithEnoughBalance) {
detail: `No user found with enough balance to cover balance shortage of ${difference} for ${user.userName}`, return {
data: [], ok: false,
}; detail: `No user found with enough balance to cover balance shortage of ${difference} for ${user.userName}`,
data: [],
};
}
console.log(
`Dude has enough balance to take on this other user's expenses ': ${JSON.stringify(userWithEnoughBalance)}`,
);
for (let i = 0; i < result.length; i++) {
if (!entriesToMove.includes(result[i].id)) {
continue;
}
const entry = result[i];
let amountMoved = 0;
if (entry.userId !== user.userId) {
continue;
}
entry.userId = userWithEnoughBalance.userId;
balanceCounts[userWithEnoughBalance.userId] +=
entry.first + entry.second;
balanceCounts[user.userId] -= entry.first + entry.second;
amountMoved += entry.first + entry.second;
if (amountMoved >= difference) {
// don't move more than the difference'
break;
}
}
console.log(
`[+] Moved ${entriesToMove.length} entries to ${userWithEnoughBalance.userName}`,
);
} }
console.log(
`Dude has enough balance to take on this other user's expenses ': ${JSON.stringify(userWithEnoughBalance)}`,
);
for (let i = 0; i < result.length; i++) {
if (!entriesToMove.includes(result[i].id)) {
continue;
}
const entry = result[i];
let amountMoved = 0;
if (entry.userId !== user.userId) {
continue;
}
entry.userId = userWithEnoughBalance.userId;
balanceCounts[userWithEnoughBalance.userId] += entry.first + entry.second;
balanceCounts[user.userId] -= entry.first + entry.second;
amountMoved += entry.first + entry.second;
if (amountMoved >= difference) {
// don't move more than the difference'
break;
}
}
console.log(
`[+] Moved ${entriesToMove.length} entries to ${userWithEnoughBalance.userName}`,
);
}
} }
export async function fetchPostDataHistory(input: PostDataHistoryFilters) { export async function fetchPostDataHistory(input: PostDataHistoryFilters) {
const { draw, date } = input; const { draw, date } = input;
console.log(`Fetching post data from HISTORY for draw: ${date} - ${draw.id}`); console.log(
const found = await dbApiPostData.getPostDataByDraw(date, draw.id); `Fetching post data from HISTORY for draw: ${date} - ${draw.id}`,
if (!found) { );
return { data: [], users: [], ok: false, detail: "Data not found" }; const found = await dbApiPostData.getPostDataByDraw(date, draw.id);
} if (!found) {
console.log( return { data: [], users: [], ok: false, detail: "Data not found" };
`Data found for the passed draw: ${date} - ${draw.id}, returning that`,
);
const users = await dbApiUser.getAllPostUsers();
const uniqueUserIds = [] as string[];
for (const each of found) {
if (!each.userId || uniqueUserIds.includes(each.userId)) {
continue;
} }
uniqueUserIds.push(each.userId); console.log(
} `Data found for the passed draw: ${date} - ${draw.id}, returning that`,
return { );
data: found, const users = await dbApiUser.getAllPostUsers();
users: users.filter((u) => uniqueUserIds.includes(u.userId)), const uniqueUserIds = [] as string[];
ok: true, for (const each of found) {
detail: "Data found", if (!each.userId || uniqueUserIds.includes(each.userId)) {
}; continue;
}
uniqueUserIds.push(each.userId);
}
return {
data: found,
users: users.filter((u) => uniqueUserIds.includes(u.userId)),
ok: true,
detail: "Data found",
};
} }

View File

@@ -7,108 +7,110 @@ import { z } from "zod";
import { dbApiUser } from "$lib/server/db/apiuser.db"; import { dbApiUser } from "$lib/server/db/apiuser.db";
import type { ServerError } from "$lib/utils/data.types"; import type { ServerError } from "$lib/utils/data.types";
import { import {
isSessionValidInStore, isSessionValidInStore,
removeSessionFromStore, removeSessionFromStore,
setSessionToRedis, setSessionToRedis,
} from "$lib/server/utils/session.service"; } from "$lib/server/utils/session.service";
export const apiAuthRouter = createTRPCRouter({ export const apiAuthRouter = createTRPCRouter({
getCaptcha: protectedProcedure.mutation(async () => { getCaptcha: protectedProcedure.mutation(async () => {
try { try {
const uuid = getUUID(); const uuid = getUUID();
const res = await fetch( const res = await fetch(
`${constants.SCRAP_API_URL}/verify/image?uuid=${uuid}`, `${constants.SCRAP_API_URL}/verify/image?uuid=${uuid}`,
{ {
headers: { headers: {
...constants.SCRAP_API_BASE_HEADERS, ...constants.SCRAP_API_BASE_HEADERS,
Accept: Accept: "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8",
"image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", },
}, },
}, );
); const bloob = await res.blob();
const bloob = await res.blob(); const imageBuffer = Buffer.from(await bloob.arrayBuffer());
const imageBuffer = Buffer.from(await bloob.arrayBuffer()); const base64String = imageBuffer.toString("base64");
const base64String = imageBuffer.toString("base64"); return { id: uuid, image: base64String };
return { id: uuid, image: base64String }; } catch (err) {
} catch (err) { console.log(err);
console.log(err); throw new TRPCError({
throw new TRPCError({ code: "INTERNAL_SERVER_ERROR",
code: "INTERNAL_SERVER_ERROR", message: "Error getting captcha image.",
message: "Error getting captcha image.", });
});
}
}),
getNewSession: protectedProcedure
.input(
z.object({
captchaId: z.string().min(1),
captchaAnswer: z.string().min(1),
userId: z.string().optional(),
}),
)
.mutation(async ({ input }) => {
console.log("[=] Getting new session... ", input);
try {
const { captchaId, captchaAnswer } = input;
let { userId, userType, password } =
await dbApiUser.getRandomDistributor();
if (input.userId) {
let _user = await dbApiUser.getUserById(input.userId);
console.log("[=] User :: ", _user?.userId);
if (!_user) {
return {
success: false,
errors: [{ message: "User not found." }],
};
}
userId = _user.userId;
userType = _user.userType;
password = _user.password;
} }
console.log(`[=] Getting session token for user ${userId}...`);
const token = await getSessionToken({
code: captchaAnswer,
verifyToken: captchaId,
userId: userId,
userType: userType,
password: password,
});
console.log("[=] Token Response :: ", JSON.stringify(token, null, 2));
if (!token.ok) {
return {
success: false,
errors: [{ message: token.message }],
};
}
await setSessionToRedis(token.message, input.userId ?? "");
return { success: true, errors: [] as ServerError };
} catch (err) {
console.log(err);
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Error getting new session.",
});
}
}), }),
isApiSessionValid: protectedProcedure getNewSession: protectedProcedure
.input( .input(
z.object({ z.object({
checkingUserSession: z.boolean(), captchaId: z.string().min(1),
userId: z.string().optional(), captchaAnswer: z.string().min(1),
}), userId: z.string().optional(),
) }),
.query(async ({ input }) => { )
return { valid: await isSessionValidInStore(input.userId) }; .mutation(async ({ input }) => {
}), console.log("[=] Getting new session... ", input);
try {
const { captchaId, captchaAnswer } = input;
let { userId, userType, password } =
await dbApiUser.getRandomDistributor();
logoutUser: protectedProcedure if (input.userId) {
.input(z.object({ userId: z.string().optional() })) let _user = await dbApiUser.getUserById(input.userId);
.mutation(async ({ input }) => { console.log("[=] User :: ", _user?.userId);
const { userId } = input; if (!_user) {
await removeSessionFromStore(userId); return {
return { success: true, errors: [] as ServerError }; success: false,
}), errors: [{ message: "User not found." }],
};
}
userId = _user.userId;
userType = _user.userType;
password = _user.password;
}
console.log(`[=] Getting session token for user ${userId}...`);
const token = await getSessionToken({
code: captchaAnswer,
verifyToken: captchaId,
userId: userId,
userType: userType,
password: password,
});
console.log(
"[=] Token Response :: ",
JSON.stringify(token, null, 2),
);
if (!token.ok) {
return {
success: false,
errors: [{ message: token.message }],
};
}
await setSessionToRedis(token.message, input.userId ?? "");
return { success: true, errors: [] as ServerError };
} catch (err) {
console.log(err);
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Error getting new session.",
});
}
}),
isApiSessionValid: protectedProcedure
.input(
z.object({
checkingUserSession: z.boolean(),
userId: z.string().optional(),
}),
)
.query(async ({ input }) => {
return { valid: await isSessionValidInStore(input.userId) };
}),
logoutUser: protectedProcedure
.input(z.object({ userId: z.string().optional() }))
.mutation(async ({ input }) => {
const { userId } = input;
await removeSessionFromStore(userId);
return { success: true, errors: [] as ServerError };
}),
}); });

View File

@@ -7,181 +7,192 @@ import { getReducedFinalSheet } from "$lib/server/finalsheet.helpers";
import { getDefaultTotals, getULID } from "$lib/utils"; import { getDefaultTotals, getULID } from "$lib/utils";
import { constants } from "$lib/utils/constants"; import { constants } from "$lib/utils/constants";
import { import {
ApiUserTypes, ApiUserTypes,
type APISession, type APISession,
type ReducedFinalSheetData, type ReducedFinalSheetData,
type ServerError, type ServerError,
} from "$lib/utils/data.types"; } from "$lib/utils/data.types";
import { z } from "zod"; import { z } from "zod";
import { createTRPCRouter, protectedProcedure } from "../t"; import { createTRPCRouter, protectedProcedure } from "../t";
const lastFetched = { const lastFetched = {
get: async () => { get: async () => {
const out = await redis.get(constants.LAST_FETCHED_KEY); const out = await redis.get(constants.LAST_FETCHED_KEY);
if (out === null) { if (out === null) {
return "Not fetched yet"; return "Not fetched yet";
} }
return out; return out;
}, },
set: async () => { set: async () => {
await redis.set(constants.LAST_FETCHED_KEY, new Date().toISOString()); await redis.set(constants.LAST_FETCHED_KEY, new Date().toISOString());
}, },
}; };
export const apiDataRouter = createTRPCRouter({ export const apiDataRouter = createTRPCRouter({
getDealersAndDraws: protectedProcedure.query(async () => { getDealersAndDraws: protectedProcedure.query(async () => {
const draws = await dbDraw.getAllDraws(true); const draws = await dbDraw.getAllDraws(true);
const dealers = await dbApiUser.allUsersOfType(ApiUserTypes.DEALER); const dealers = await dbApiUser.allUsersOfType(ApiUserTypes.DEALER);
const lf = await lastFetched.get(); const lf = await lastFetched.get();
return { users: dealers, draws, lastFetched: lf }; return { users: dealers, draws, lastFetched: lf };
}),
refetchData: protectedProcedure
.input(
z.object({
userIds: z.array(z.string()),
drawId: z.string(),
targetDate: z.string(),
}),
)
.mutation(async ({ input }) => {
const { userIds, targetDate, drawId } = input;
if (userIds.length < 1) {
return {
detail: "No users selected",
success: false,
errors: [
{ message: "No users selected to refetch data for" },
] as ServerError,
};
}
const sess = JSON.parse(
(await redis.get(constants.SCRAP_API_SESSION_KEY)) ?? "",
) as APISession;
if (sess === null) {
return {
detail: "API Session expired",
success: false,
errors: [
{
message:
"API Session expired, get a new api session and try again",
},
] as ServerError,
};
}
const userIdsInt = userIds.map((x) => parseInt(x.split(":")[1]));
const out = await getData(
sess.sessionToken,
userIdsInt,
parseInt(drawId.split(":")[1]),
targetDate,
);
if (!out.ok) {
return {
success: false,
detail: "Error fetching data",
errors: [{ message: out.message }] as ServerError,
};
}
const dataCount = out.data.length;
await dbApiData.upsertData(out.data, targetDate);
return {
detail: `Scraped ${dataCount} entries for ${userIds.length} users`,
success: true,
errors: [] as ServerError,
};
}), }),
getDataByFilters: protectedProcedure refetchData: protectedProcedure
.input( .input(
z.object({ date: z.string(), drawId: z.string(), userId: z.string() }), z.object({
) userIds: z.array(z.string()),
.mutation(async ({ input }) => { drawId: z.string(),
const { date, drawId, userId } = input; targetDate: z.string(),
const data = await dbApiData.getBookingEntriesForDealer( }),
date, )
drawId.split(":")[1], .mutation(async ({ input }) => {
userId.split(":")[1], const { userIds, targetDate, drawId } = input;
true, if (userIds.length < 1) {
); return {
return { data }; detail: "No users selected",
success: false,
errors: [
{ message: "No users selected to refetch data for" },
] as ServerError,
};
}
const sess = JSON.parse(
(await redis.get(constants.SCRAP_API_SESSION_KEY)) ?? "",
) as APISession;
if (sess === null) {
return {
detail: "API Session expired",
success: false,
errors: [
{
message:
"API Session expired, get a new api session and try again",
},
] as ServerError,
};
}
console.log(
`Fetching data for ${userIds.length} users for draw ${drawId}`,
);
const userIdsInt = userIds.map((x) => parseInt(x.split(":")[1]));
const out = await getData(
sess.sessionToken,
userIdsInt,
parseInt(drawId.split(":")[1]),
targetDate,
);
if (!out.ok) {
return {
success: false,
detail: "Error fetching data",
errors: [{ message: out.message }] as ServerError,
};
}
const dataCount = out.data.length;
await dbApiData.upsertData(out.data, targetDate);
return {
detail: `Scraped ${dataCount} entries for ${userIds.length} users`,
success: true,
errors: [] as ServerError,
};
}),
getDataByFilters: protectedProcedure
.input(
z.object({
date: z.string(),
drawId: z.string(),
userId: z.string(),
}),
)
.mutation(async ({ input }) => {
const { date, drawId, userId } = input;
const data = await dbApiData.getBookingEntriesForDealer(
date,
drawId.split(":")[1],
userId.split(":")[1],
true,
);
return { data };
}),
getReducedFinalSheet: protectedProcedure
.input(z.object({ date: z.string(), drawId: z.string() }))
.mutation(async ({ input }) => {
const { date, drawId } = input;
const draw = await dbDraw.getDraw(drawId);
const fsData = {
id: getULID(),
date,
drawId,
data: [],
totals: getDefaultTotals(),
} as ReducedFinalSheetData;
if (!draw) {
return {
ok: false,
detail: `Draw for the passed draw ID not found`,
data: fsData,
errors: [
{ message: `Draw for the passed draw ID not found` },
] as ServerError,
};
}
console.log("Fetching data");
const data = await getReducedFinalSheet(fsData);
console.log(data);
if (!data.ok) {
return {
ok: false,
detail: `Error compiling final sheet`,
data: fsData,
errors: data.errors,
};
}
return {
ok: true,
detail: `Final sheet for ${date}, draw ${draw.title} has been compiled`,
data: fsData,
errors: [] as ServerError,
};
}),
getFinalSheetRow: protectedProcedure
.input(
z.object({
date: z.string(),
drawId: z.string(),
number: z.string(),
}),
)
.mutation(async ({ input }) => {
return {
ok: true,
data: {},
errors: [] as ServerError,
};
}),
delDataOlderThan2Weeks: protectedProcedure.mutation(async () => {
await dbApiData.deleteDataOlderThan2Weeks();
return { ok: true, detail: "Data older than 2 weeks has been deleted" };
}), }),
getReducedFinalSheet: protectedProcedure postTestBooking: protectedProcedure
.input(z.object({ date: z.string(), drawId: z.string() })) .input(z.object({ drawId: z.string(), date: z.string() }))
.mutation(async ({ input }) => { .mutation(async () => {
const { date, drawId } = input; return {
const draw = await dbDraw.getDraw(drawId); ok: true,
const fsData = { detail: "API not live",
id: getULID(), errors: [] as ServerError,
date, };
drawId, // console.log("GENERATING TEST DATA :: ", drawId, date);
data: [], // const testData = await getTestBookingData(drawId, date);
totals: getDefaultTotals(), // // console.log(testData);
} as ReducedFinalSheetData; // await dbApiData.upsertData(testData, date);
if (!draw) { // return {
return { // ok: true,
ok: false, // detail: "Test booking committed",
detail: `Draw for the passed draw ID not found`, // errors: [] as ServerError,
data: fsData, // };
errors: [ }),
{ message: `Draw for the passed draw ID not found` },
] as ServerError,
};
}
console.log("Fetching data");
const data = await getReducedFinalSheet(fsData);
console.log(data);
if (!data.ok) {
return {
ok: false,
detail: `Error compiling final sheet`,
data: fsData,
errors: data.errors,
};
}
return {
ok: true,
detail: `Final sheet for ${date}, draw ${draw.title} has been compiled`,
data: fsData,
errors: [] as ServerError,
};
}),
getFinalSheetRow: protectedProcedure
.input(
z.object({ date: z.string(), drawId: z.string(), number: z.string() }),
)
.mutation(async ({ input }) => {
return {
ok: true,
data: {},
errors: [] as ServerError,
};
}),
delDataOlderThan2Weeks: protectedProcedure.mutation(async () => {
await dbApiData.deleteDataOlderThan2Weeks();
return { ok: true, detail: "Data older than 2 weeks has been deleted" };
}),
postTestBooking: protectedProcedure
.input(z.object({ drawId: z.string(), date: z.string() }))
.mutation(async () => {
return {
ok: true,
detail: "API not live",
errors: [] as ServerError,
};
// console.log("GENERATING TEST DATA :: ", drawId, date);
// const testData = await getTestBookingData(drawId, date);
// // console.log(testData);
// await dbApiData.upsertData(testData, date);
// return {
// ok: true,
// detail: "Test booking committed",
// errors: [] as ServerError,
// };
}),
}); });

View File

@@ -4,34 +4,30 @@ import { dbApiUser } from "$lib/server/db/apiuser.db";
import { z } from "zod"; import { z } from "zod";
export const apiUserRouter = createTRPCRouter({ export const apiUserRouter = createTRPCRouter({
getAllDistributors: protectedProcedure.query(async () => { getAllDistributors: protectedProcedure.query(async () => {
return await dbApiUser.allUsersOfType(ApiUserTypes.DISTRIBUTOR); return await dbApiUser.allUsersOfType(ApiUserTypes.DISTRIBUTOR);
}),
getAllDealers: protectedProcedure.query(async () => {
return await dbApiUser.allUsersOfType(ApiUserTypes.DEALER);
}),
getAllDistributorsCount: protectedProcedure.query(async () => {
return await dbApiUser.getUserTypeCount(ApiUserTypes.DISTRIBUTOR);
}),
getAllDealersCount: protectedProcedure.query(async () => {
return await dbApiUser.getUserTypeCount(ApiUserTypes.DEALER);
}),
getDistributorsWithTheirChildren: protectedProcedure.query(async () => {
const users = await dbApiUser.getAllDistributorsWithTheirChildren();
return { users };
}),
getAllDealersPostUserFormat: protectedProcedure.query(async () => {
return await dbApiUser.allUsersOfTypeLimitedInfo(ApiUserTypes.DEALER);
}),
getAllPostUsers: protectedProcedure.query(async () => {
return await dbApiUser.getAllPostUsers();
}),
setPostDataFlagForUser: protectedProcedure
.input(z.object({ users: z.array(zApiPostUser) }))
.mutation(async ({ input }) => {
await dbApiUser.setPostDataFlagForUsers(input.users);
}), }),
getAllDealers: protectedProcedure.query(async () => {
return await dbApiUser.allUsersOfType(ApiUserTypes.DEALER);
}),
getAllDistributorsCount: protectedProcedure.query(async () => {
return await dbApiUser.getUserTypeCount(ApiUserTypes.DISTRIBUTOR);
}),
getAllDealersCount: protectedProcedure.query(async () => {
return await dbApiUser.getUserTypeCount(ApiUserTypes.DEALER);
}),
getAllDealersPostUserFormat: protectedProcedure.query(async () => {
return await dbApiUser.allUsersOfTypeLimitedInfo(ApiUserTypes.DEALER);
}),
getAllPostUsers: protectedProcedure.query(async () => {
return await dbApiUser.getAllPostUsers();
}),
setPostDataFlagForUser: protectedProcedure
.input(z.object({ users: z.array(zApiPostUser) }))
.mutation(async ({ input }) => {
await dbApiUser.setPostDataFlagForUsers(input.users);
}),
}); });

View File

@@ -3,70 +3,70 @@ import { createTRPCRouter, protectedProcedure } from "../t";
import { dbDraw } from "$lib/server/db/apidraw.db"; import { dbDraw } from "$lib/server/db/apidraw.db";
import { DEFAULT_TZ } from "$lib/utils/constants"; import { DEFAULT_TZ } from "$lib/utils/constants";
import { import {
zBookingEntry, zBookingEntry,
type BookingEntry, type BookingEntry,
type ServerError, type ServerError,
} from "$lib/utils/data.types"; } from "$lib/utils/data.types";
import { surreal } from "$lib/server/connectors/surreal.db"; import { surreal } from "$lib/server/connectors/surreal.db";
import { parseToDateString } from "$lib/utils/datetime.helper.utils"; import { parseToDateString } from "$lib/utils/datetime.helper.utils";
function getTodaysTableName() { function getTodaysTableName() {
const today = parseToDateString(new Date()); const today = parseToDateString(new Date());
return `booking${today.replaceAll("-", "")}`; return `booking${today.replaceAll("-", "")}`;
} }
export const bookingRouter = createTRPCRouter({ export const bookingRouter = createTRPCRouter({
getPanelData: protectedProcedure.query(async () => { getPanelData: protectedProcedure.query(async () => {
const draws = await dbDraw.getAllDraws(true); const draws = await dbDraw.getAllDraws(true);
const timeInDrawsTz = new Date().toLocaleString("en-US", { const timeInDrawsTz = new Date().toLocaleString("en-US", {
timeZone: DEFAULT_TZ, timeZone: DEFAULT_TZ,
}); });
return { draws, timeInDrawsTz: timeInDrawsTz }; return { draws, timeInDrawsTz: timeInDrawsTz };
}),
getBookingData: protectedProcedure
.input(z.object({ drawId: z.string() }))
.mutation(async ({ input }) => {
const { drawId } = input;
const date = parseToDateString(new Date());
const tn = getTodaysTableName();
const did = parseInt(drawId.split(":")[1]);
const [out] = await surreal.query<[BookingEntry[]]>(
`select * from type::table($table) where drawId = $drawId and bookDate = $bookDate order by requestId desc`,
{ table: tn, drawId: did, bookDate: date }
);
return { data: out.result ?? [], errors: [] as ServerError };
}), }),
syncBooking: protectedProcedure getBookingData: protectedProcedure
.input(z.object({ data: z.array(zBookingEntry) })) .input(z.object({ drawId: z.string() }))
.mutation(async ({ input }) => { .mutation(async ({ input }) => {
const tableName = getTodaysTableName(); const { drawId } = input;
const syncedEntriesIds = [] as string[]; const date = parseToDateString(new Date());
if (input.data.length > 0) { const tn = getTodaysTableName();
await surreal.insert<BookingEntry>( const did = parseInt(drawId.split(":")[1]);
tableName, const [out] = await surreal.query<[BookingEntry[]]>(
input.data.map((e) => { `select * from type::table($table) where drawId = $drawId and bookDate = $bookDate order by requestId desc`,
syncedEntriesIds.push(`${e.id}`); { table: tn, drawId: did, bookDate: date },
return { );
...e, return { data: out ?? [], errors: [] as ServerError };
createdAt: new Date().toISOString(), }),
updatedAt: new Date().toISOString(),
};
})
);
}
return { detail: "Add Booking api donezo", syncedEntriesIds };
}),
deleteBooking: protectedProcedure syncBooking: protectedProcedure
.input(z.object({ bookingIds: z.array(z.string()) })) .input(z.object({ data: z.array(zBookingEntry) }))
.mutation(async ({ input }) => { .mutation(async ({ input }) => {
await Promise.all( const tableName = getTodaysTableName();
input.bookingIds.map(async (id) => { const syncedEntriesIds = [] as string[];
await surreal.delete(id); if (input.data.length > 0) {
}) await surreal.insert<BookingEntry>(
); tableName,
return { detail: `Deleted ${input.bookingIds.length} Entries` }; input.data.map((e) => {
}), syncedEntriesIds.push(`${e.id}`);
return {
...e,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
}),
);
}
return { detail: "Add Booking api donezo", syncedEntriesIds };
}),
deleteBooking: protectedProcedure
.input(z.object({ bookingIds: z.array(z.string()) }))
.mutation(async ({ input }) => {
await Promise.all(
input.bookingIds.map(async (id) => {
await surreal.delete(id);
}),
);
return { detail: `Deleted ${input.bookingIds.length} Entries` };
}),
}); });

View File

@@ -4,27 +4,28 @@ import { z } from "zod";
import { zDraw } from "$lib/utils/data.types"; import { zDraw } from "$lib/utils/data.types";
export const drawRouter = createTRPCRouter({ export const drawRouter = createTRPCRouter({
getAllDraws: protectedProcedure.query(async () => { getAllDraws: protectedProcedure.query(async () => {
return await dbDraw.getAllDraws(true); return await dbDraw.getAllDraws(true);
}),
getCurrentTime: protectedProcedure.query(async () => {
const now = new Date();
const timezone = "Asia/Karachi";
const nowKarachi = new Date(
now.toLocaleString("en-US", { timeZone: timezone }),
);
// console.log(nowKarachi.toLocaleString());
return { now: nowKarachi };
}),
savePresetInfoForDraws: protectedProcedure
.input(z.object({ draws: z.array(zDraw) }))
.mutation(async ({ input }) => {
// console.log("savePresetInfoForDraws", input);
for (const draw of input.draws) {
await dbDraw.updateDrawPresetInfo(draw);
}
return { success: true };
}), }),
getCurrentTime: protectedProcedure.query(async () => {
const now = new Date();
const timezone = "Asia/Karachi";
const nowKarachi = new Date(
now.toLocaleString("en-US", { timeZone: timezone }),
);
// console.log(nowKarachi.toLocaleString());
return { now: nowKarachi };
}),
savePresetInfoForDraws: protectedProcedure
.input(z.object({ draws: z.array(zDraw) }))
.mutation(async ({ input }) => {
console.log("Saving preset info for draws");
for (const draw of input.draws) {
await dbDraw.updateDrawPresetInfo(draw);
}
console.log("Done saving preset info for draws");
return { success: true };
}),
}); });

View File

@@ -1,265 +1,259 @@
import { z } from "zod"; import { z } from "zod";
export type Session = { export type Session = {
sId: string; sId: string;
ip: string; ip: string;
userAgent: string; userAgent: string;
username: string; username: string;
userType: string; userType: string;
}; };
export type APISession = { export type APISession = {
ip: string; ip: string;
sessionToken: string; sessionToken: string;
userId: string; userId: string;
}; };
export const zAuthPayload = z.object({ export const zAuthPayload = z.object({
username: z.string().min(4).max(64), username: z.string().min(4).max(64),
password: z.string().min(8).max(64), password: z.string().min(8).max(64),
}); });
export const zUser = z.object({ export const zUser = z.object({
id: z.string().length(16), id: z.string().length(16),
createdAt: z.string(), createdAt: z.string(),
updatedAt: z.string(), updatedAt: z.string(),
username: z.string().min(4).max(64), username: z.string().min(4).max(64),
password: z.string().min(8).max(64), password: z.string().min(8).max(64),
userType: z.string().min(4).max(5), userType: z.string().min(4).max(5),
association: z.string(), association: z.string(),
}); });
export type User = z.infer<typeof zUser>;
export const zLooseUser = z.object({ export const zLooseUser = z.object({
id: z.string().length(16).optional(), id: z.string().length(16).optional(),
createdAt: z.string().optional(), createdAt: z.string().optional(),
updatedAt: z.string().optional(), updatedAt: z.string().optional(),
username: z.string().min(4).max(64), username: z.string().min(4).max(64),
password: z.string().min(8).max(64), password: z.string().min(8).max(64),
userType: z.string().min(4).max(5), userType: z.string().min(4).max(5),
association: z.string(), association: z.string(),
}); });
export type LooseUser = z.infer<typeof zLooseUser>;
export const zApiUser = z.object({ export const zApiUser = z.object({
id: z.string().length(16), id: z.string().length(16),
userType: z.number(), userType: z.number(),
disableBooking: z.string().nullable().optional(), disableBooking: z.string().nullable().optional(),
sendVoucher: z.string().nullable().optional(), sendVoucher: z.string().nullable().optional(),
voucherGenerated: z.string().nullable().optional(), voucherGenerated: z.string().nullable().optional(),
parentAdmin: z.number(), parentAdmin: z.number(),
parentDistributor: z.number(), parentDistributor: z.number(),
userName: z.string(), userName: z.string(),
userCity: z.string().nullable().optional(), userCity: z.string().nullable().optional(),
userId: z.string(), userId: z.string(),
password: z.string(), password: z.string(),
accessDenied: z.number(), accessDenied: z.number(),
phoneNumber: z.string(), phoneNumber: z.string(),
emailAddress: z.string(), emailAddress: z.string(),
disable: z.number(), disable: z.number(),
commission: z.number(), commission: z.number(),
commissionPangora: z.number(), commissionPangora: z.number(),
allowTitles: z.string(), allowTitles: z.string(),
specialDealer: z.number(), specialDealer: z.number(),
allowBalance: z.number(), allowBalance: z.number(),
balance: z.number(), balance: z.number(),
profitlossShare: z.number(), profitlossShare: z.number(),
shareProfitonly: z.number(), shareProfitonly: z.number(),
allowRemoveold: z.number(), allowRemoveold: z.number(),
removeDays: z.number().nullable().optional(), removeDays: z.number().nullable().optional(),
language: z.number(), language: z.number(),
postData: z.boolean().nullable().optional(), postData: z.boolean().nullable().optional(),
createdAt: z.string().nullable(), createdAt: z.string().nullable(),
updatedAt: z.string().nullable(), updatedAt: z.string().nullable(),
}); });
export type ApiUser = z.infer<typeof zApiUser>;
export const zApiPostUser = z.object({ export const zApiPostUser = z.object({
id: z.string(), id: z.string(),
userName: z.string(), userName: z.string(),
userId: z.string(), userId: z.string(),
postData: z.boolean(), postData: z.boolean(),
balance: z.number().optional(), balance: z.number().optional(),
}); });
export type ApiPostUser = z.infer<typeof zApiPostUser>;
export const zLooseApiUser = z.object({ export const zLooseApiUser = z.object({
id: z.string().length(16).optional(), id: z.string().length(16).optional(),
userType: z.number().optional(), userType: z.number().optional(),
disableBooking: z.string().nullable().optional(), disableBooking: z.string().nullable().optional(),
sendVoucher: z.string().nullable().optional(), sendVoucher: z.string().nullable().optional(),
voucherGenerated: z.string().nullable().optional(), voucherGenerated: z.string().nullable().optional(),
parentAdmin: z.number(), parentAdmin: z.number(),
parentDistributor: z.number(), parentDistributor: z.number(),
userName: z.string(), userName: z.string(),
userCity: z.string().nullable().optional(), userCity: z.string().nullable().optional(),
userId: z.string().optional(), userId: z.string().optional(),
password: z.string(), password: z.string(),
accessDenied: z.number(), accessDenied: z.number(),
phoneNumber: z.string(), phoneNumber: z.string(),
emailAddress: z.string(), emailAddress: z.string(),
disable: z.number(), disable: z.number(),
commission: z.number(), commission: z.number(),
commissionPangora: z.number(), commissionPangora: z.number(),
allowTitles: z.string(), allowTitles: z.string(),
specialDealer: z.number(), specialDealer: z.number(),
allowBalance: z.number(), allowBalance: z.number(),
balance: z.number(), balance: z.number(),
profitlossShare: z.number(), profitlossShare: z.number(),
shareProfitonly: z.number(), shareProfitonly: z.number(),
allowRemoveold: z.number(), allowRemoveold: z.number(),
removeDays: z.number().nullable().optional(), removeDays: z.number().nullable().optional(),
language: z.number().optional(), language: z.number().optional(),
postData: z.boolean().nullable().optional(), postData: z.boolean().nullable().optional(),
createdAt: z.string().nullable().optional(), createdAt: z.string().nullable().optional(),
updatedAt: z.string().nullable().optional(), updatedAt: z.string().nullable().optional(),
}); });
export type LooseApiUser = z.infer<typeof zLooseApiUser>;
export const zDraw = z.object({ export const zDraw = z.object({
id: z.string(), id: z.string(),
title: z.string(), title: z.string(),
closeTime: z.string(), closeTime: z.string(),
filterDuplicatesWhilePosting: z.boolean(), filterDuplicatesWhilePosting: z.boolean(),
drawType: z.number(), drawType: z.number(),
adminId: z.number(), adminId: z.number(),
abRateF: z.coerce.number(), abRateF: z.coerce.number(),
abRateS: z.coerce.number(), abRateS: z.coerce.number(),
abcRateF: z.coerce.number(), abcRateF: z.coerce.number(),
abcRateS: z.coerce.number(), abcRateS: z.coerce.number(),
createdAt: z.string().nullable().optional(), createdAt: z.string().nullable().optional(),
updatedAt: z.string().nullable().optional(), updatedAt: z.string().nullable().optional(),
}); });
export type Draw = z.infer<typeof zDraw>; export type Draw = z.infer<typeof zDraw>;
export const zBookingEntry = z.object({ export const zBookingEntry = z.object({
id: z.string(), id: z.string(),
distributorId: z.number(), distributorId: z.number(),
dealerId: z.number(), dealerId: z.number(),
drawId: z.number(), drawId: z.number(),
bookDate: z.string(), bookDate: z.string(),
number: z.string(), number: z.string(),
first: z.number(), first: z.number(),
second: z.number(), second: z.number(),
changedBalance: z.number(), changedBalance: z.number(),
sheetName: z.string().nullable().optional(), sheetName: z.string().nullable().optional(),
sheetId: z.string().nullable().optional(), sheetId: z.string().nullable().optional(),
requestId: z.string(), requestId: z.string(),
createdAt: z.string().nullable().optional(), createdAt: z.string().nullable().optional(),
updatedAt: z.string().nullable().optional(), updatedAt: z.string().nullable().optional(),
}); });
export type BookingEntry = z.infer<typeof zBookingEntry>; export type BookingEntry = z.infer<typeof zBookingEntry>;
export const zPostDataEntry = z.object({ export const zPostDataEntry = z.object({
id: z.string(), id: z.string(),
requestId: z.string().nullable().optional(), requestId: z.string().nullable().optional(),
number: z.string(), number: z.string(),
first: z.number(), first: z.number(),
second: z.number(), second: z.number(),
userId: z.string().nullable().optional(), userId: z.string().nullable().optional(),
createdAt: z.string().nullable().optional(), createdAt: z.string().nullable().optional(),
updatedAt: z.string().nullable().optional(), updatedAt: z.string().nullable().optional(),
}); });
export type PostDataEntry = z.infer<typeof zPostDataEntry>; export type PostDataEntry = z.infer<typeof zPostDataEntry>;
const zPostDataHistory = z.object({ const zPostDataHistory = z.object({
id: z.string(), id: z.string(),
data: z.array(zPostDataEntry), data: z.array(zPostDataEntry),
drawId: z.number(), drawId: z.number(),
bookDate: z.string(), bookDate: z.string(),
createdAt: z.string().nullable().optional(), createdAt: z.string().nullable().optional(),
updatedAt: z.string().nullable().optional(), updatedAt: z.string().nullable().optional(),
}); });
export type PostDataHistory = z.infer<typeof zPostDataHistory>; export type PostDataHistory = z.infer<typeof zPostDataHistory>;
export const zPresetDataEntry = z.object({ export const zPresetDataEntry = z.object({
id: z.string(), id: z.string(),
drawId: z.number(), drawId: z.number(),
bookDate: z.string(), bookDate: z.string(),
number: z.string(), number: z.string(),
first: z.number(), first: z.number(),
second: z.number(), second: z.number(),
createdAt: z.string().nullable().optional(), createdAt: z.string().nullable().optional(),
dealerId: z.number().optional().nullable(), dealerId: z.number().optional().nullable(),
}); });
export type PresetDataEntry = z.infer<typeof zPresetDataEntry>; export type PresetDataEntry = z.infer<typeof zPresetDataEntry>;
export const fsPair = z.object({ export const fsPair = z.object({
first: z.number(), first: z.number(),
second: z.number(), second: z.number(),
}); });
export const zLexiCodeCacheObject = z.object({ export const zLexiCodeCacheObject = z.object({
number: z.string(), number: z.string(),
rate: fsPair, rate: fsPair,
prize: fsPair, prize: fsPair,
frequency: fsPair, frequency: fsPair,
}); });
export const reducedFinalSheetRow = z.object({ export const reducedFinalSheetRow = z.object({
id: z.string(), id: z.string(),
number: z.string(), number: z.string(),
frequency: fsPair, frequency: fsPair,
frequencies: z.object({ frequencies: z.object({
// a: fsPair, // a: fsPair,
// ab: fsPair, // ab: fsPair,
// abc: fsPair, // abc: fsPair,
// "+abc": fsPair, // "+abc": fsPair,
// "a+bc": fsPair, // "a+bc": fsPair,
// "ab+c": fsPair, // "ab+c": fsPair,
abcd: fsPair, abcd: fsPair,
}), }),
rate: fsPair, rate: fsPair,
prize: fsPair, prize: fsPair,
profit: fsPair, profit: fsPair,
}); });
export const zfinalSheetRow = z.object({ export const zfinalSheetRow = z.object({
id: z.string(), id: z.string(),
number: z.string(), number: z.string(),
frequency: fsPair, frequency: fsPair,
rate: fsPair, rate: fsPair,
prize: fsPair, prize: fsPair,
profit: fsPair, profit: fsPair,
a: zLexiCodeCacheObject, a: zLexiCodeCacheObject,
xa: zLexiCodeCacheObject, xa: zLexiCodeCacheObject,
xxa: zLexiCodeCacheObject, xxa: zLexiCodeCacheObject,
xxxa: zLexiCodeCacheObject, xxxa: zLexiCodeCacheObject,
ab: zLexiCodeCacheObject, ab: zLexiCodeCacheObject,
xab: zLexiCodeCacheObject, xab: zLexiCodeCacheObject,
axb: zLexiCodeCacheObject, axb: zLexiCodeCacheObject,
xaxb: zLexiCodeCacheObject, xaxb: zLexiCodeCacheObject,
xxab: zLexiCodeCacheObject, xxab: zLexiCodeCacheObject,
axxb: zLexiCodeCacheObject, axxb: zLexiCodeCacheObject,
abc: zLexiCodeCacheObject, abc: zLexiCodeCacheObject,
xabc: zLexiCodeCacheObject, xabc: zLexiCodeCacheObject,
axbc: zLexiCodeCacheObject, axbc: zLexiCodeCacheObject,
abxc: zLexiCodeCacheObject, abxc: zLexiCodeCacheObject,
abcd: zLexiCodeCacheObject, abcd: zLexiCodeCacheObject,
}); });
export type ServerError = Array<{ export type ServerError = Array<{
message: string; message: string;
value?: string; value?: string;
meta?: any; meta?: any;
}>; }>;
export const UserTypes = { ADMIN: "ADMIN", USER: "USER" }; export const UserTypes = { ADMIN: "ADMIN", USER: "USER" };
export const ApiUserTypes = { ADMIN: 1, DISTRIBUTOR: 2, DEALER: 3 }; export const ApiUserTypes = { ADMIN: 1, DISTRIBUTOR: 2, DEALER: 3 };
export type User = z.infer<typeof zUser>;
export type LooseUser = z.infer<typeof zLooseUser>;
export type ApiUser = z.infer<typeof zApiUser>;
export type ApiPostUser = z.infer<typeof zApiPostUser>;
export type ApiPostUserWithParent = ApiPostUser & { export type ApiPostUserWithParent = ApiPostUser & {
parentAdmin: number; parentAdmin: number;
parentDistributor: number; parentDistributor: number;
}; };
export type LooseApiUser = z.infer<typeof zLooseApiUser>;
export type LexiCodeCacheObject = z.infer<typeof zLexiCodeCacheObject>; export type LexiCodeCacheObject = z.infer<typeof zLexiCodeCacheObject>;
export type SimpleLexiCodeObject = { number: string; lexiCode: string }; export type SimpleLexiCodeObject = { number: string; lexiCode: string };
@@ -271,108 +265,108 @@ export type ReducedFinalSheetRow = z.infer<typeof reducedFinalSheetRow>;
export type FSPair = z.infer<typeof fsPair>; export type FSPair = z.infer<typeof fsPair>;
export type FSTotals = { export type FSTotals = {
rate: FSPair; rate: FSPair;
prize: FSPair; prize: FSPair;
commission: FSPair; commission: FSPair;
netRate: FSPair; netRate: FSPair;
frequency: FSPair; frequency: FSPair;
}; };
export type ReducedFinalSheetData = { export type ReducedFinalSheetData = {
id: string; id: string;
date: string; date: string;
drawId: string; drawId: string;
data: Array<ReducedFinalSheetRow>; data: Array<ReducedFinalSheetRow>;
totals: FSTotals; totals: FSTotals;
createdAt?: string; createdAt?: string;
updatedAt?: string; updatedAt?: string;
}; };
export type FinalSheetData = { export type FinalSheetData = {
id: string; id: string;
date: string; date: string;
drawId: string; drawId: string;
data: Array<FinalSheetRow>; data: Array<FinalSheetRow>;
totals: FSTotals; totals: FSTotals;
createdAt?: string; createdAt?: string;
updatedAt?: string; updatedAt?: string;
}; };
export type AuthPayload = z.infer<typeof zAuthPayload>; export type AuthPayload = z.infer<typeof zAuthPayload>;
export type SessionData = { export type SessionData = {
username: string; username: string;
userType: string; userType: string;
}; };
export type BookingInputValues = { export type BookingInputValues = {
number: string; number: string;
default: { first: string; second: string }; default: { first: string; second: string };
first: Record<string, string>; first: Record<string, string>;
second: Record<string, string>; second: Record<string, string>;
}; };
export const zPostDataHistoryFilters = z.object({ export const zPostDataHistoryFilters = z.object({
date: z.string(), date: z.string(),
draw: zDraw, draw: zDraw,
}); });
export type PostDataHistoryFilters = z.infer<typeof zPostDataHistoryFilters>; export type PostDataHistoryFilters = z.infer<typeof zPostDataHistoryFilters>;
export const zDDFilters = z.object({ export const zDDFilters = z.object({
date: z.string(), date: z.string(),
draw: zDraw.optional(), draw: zDraw.optional(),
}); });
export type DDFilters = z.infer<typeof zDDFilters>; export type DDFilters = z.infer<typeof zDDFilters>;
export const zDDUserFilters = z.object({ export const zDDUserFilters = z.object({
date: z.string(), date: z.string(),
draw: zDraw.optional(), draw: zDraw.optional(),
user: zApiUser.optional(), user: zApiUser.optional(),
}); });
export type DDUserFilters = z.infer<typeof zDDUserFilters>; export type DDUserFilters = z.infer<typeof zDDUserFilters>;
export const zPostDataFilters = z.object({ export const zPostDataFilters = z.object({
date: z.string(), date: z.string(),
draw: zDraw.optional().nullable(), draw: zDraw.optional().nullable(),
minPrize: z.coerce.number(), minPrize: z.coerce.number(),
maxPrize: z.coerce.number(), maxPrize: z.coerce.number(),
twoDigitRates: fsPair, twoDigitRates: fsPair,
threeDigitRates: fsPair, threeDigitRates: fsPair,
customData: z.string(), customData: z.string(),
}); });
export type PostDataFilters = z.infer<typeof zPostDataFilters>; export type PostDataFilters = z.infer<typeof zPostDataFilters>;
export const DEFAULT_RANDOM_DISTRIBUTOR = { export const DEFAULT_RANDOM_DISTRIBUTOR = {
id: "apiuser:6339", id: "apiuser:6339",
userType: 2, userType: 2,
disableBooking: null, disableBooking: null,
sendVoucher: null, sendVoucher: null,
voucherGenerated: null, voucherGenerated: null,
parentAdmin: 15, parentAdmin: 15,
parentDistributor: 0, parentDistributor: 0,
userName: "Baba Sagar", userName: "Baba Sagar",
userCity: "Shikar pur", userCity: "Shikar pur",
userId: "317XY3", userId: "317XY3",
password: "405613", password: "405613",
accessDenied: 0, accessDenied: 0,
phoneNumber: "", phoneNumber: "",
emailAddress: "", emailAddress: "",
disable: 0, disable: 0,
commission: 20.0, commission: 20.0,
commissionPangora: 20.0, commissionPangora: 20.0,
allowTitles: ",7,8,9,10,11,12,13,14,15,16,30,31,32,", allowTitles: ",7,8,9,10,11,12,13,14,15,16,30,31,32,",
specialDealer: 0, specialDealer: 0,
allowBalance: 1, allowBalance: 1,
balance: 30094.905, balance: 30094.905,
profitlossShare: 50.0, profitlossShare: 50.0,
shareProfitonly: 0, shareProfitonly: 0,
allowRemoveold: 0, allowRemoveold: 0,
removeDays: 30, removeDays: 30,
language: 0, language: 0,
createdAt: new Date().toString(), createdAt: new Date().toString(),
updatedAt: new Date().toString(), updatedAt: new Date().toString(),
} as unknown as ApiUser; } as unknown as ApiUser;

View File

@@ -2,54 +2,54 @@ import { fail } from "@sveltejs/kit";
import type { Actions } from "../../$types"; import type { Actions } from "../../$types";
import { ApiUserTypes, type ServerError } from "$lib/utils/data.types"; import { ApiUserTypes, type ServerError } from "$lib/utils/data.types";
import { import {
getDealers, getDealers,
getDistributors, getDistributors,
} from "$lib/server/external/api.scraping.helpers"; } from "$lib/server/external/api.scraping.helpers";
import { dbApiUser } from "$lib/server/db/apiuser.db"; import { dbApiUser } from "$lib/server/db/apiuser.db";
import { constants } from "$lib/utils/constants"; import { constants } from "$lib/utils/constants";
import fs from "fs";
import { getSessionFromStore } from "$lib/server/utils/session.service"; import { getSessionFromStore } from "$lib/server/utils/session.service";
export const actions = { export const actions = {
refetchDistributors: async () => { refetchDistributors: async () => {
const sess = await getSessionFromStore(constants.SCRAP_API_SESSION_KEY); const sess = await getSessionFromStore(constants.SCRAP_API_SESSION_KEY);
if (!sess) { if (!sess) {
return fail(400, { return fail(400, {
success: false, success: false,
errors: [{ message: "No api session found" }], errors: [{ message: "No api session found" }],
}); });
} }
const done = await getDistributors(sess.sessionToken); const done = await getDistributors(sess.sessionToken);
console.log(`[+] ${done.data.length} distributors found`); console.log(`[+] ${done.data.length} distributors found`);
// fs.writeFileSync("distributors.json", JSON.stringify(done.data, null, 2)); // fs.writeFileSync("distributors.json", JSON.stringify(done.data, null, 2));
if (!done.ok) { if (!done.ok) {
return fail(400, { return fail(400, {
success: false, success: false,
errors: [{ message: done.message }], errors: [{ message: done.message }],
}); });
} }
await dbApiUser.upsertMany(done.data, true, ApiUserTypes.DISTRIBUTOR); await dbApiUser.upsertMany(done.data, true, ApiUserTypes.DISTRIBUTOR);
return { success: true, errors: [] as ServerError }; return { success: true, errors: [] as ServerError };
}, },
refetchDealers: async () => { refetchDealers: async () => {
const sess = await getSessionFromStore(constants.SCRAP_API_SESSION_KEY); const sess = await getSessionFromStore(constants.SCRAP_API_SESSION_KEY);
if (!sess) { if (!sess) {
return fail(400, { return fail(400, {
success: false, success: false,
errors: [{ message: "No api session found" }], errors: [{ message: "No api session found" }],
}); });
} }
const distributor_ids = await dbApiUser.getAllIdsByUserType( const distributor_ids = await dbApiUser.getAllIdsByUserType(
ApiUserTypes.DISTRIBUTOR, ApiUserTypes.DISTRIBUTOR,
); );
const done = await getDealers(sess.sessionToken, distributor_ids); console.log(distributor_ids);
console.log(`[+] ${done.dealers.length} dealers found`); const done = await getDealers(sess.sessionToken, distributor_ids);
// fs.writeFileSync("dealers.json", JSON.stringify(done.dealers, null, 2)); console.log(`[+] ${done.dealers.length} dealers found`);
if (done.errors.length > 0) { // fs.writeFileSync("dealers.json", JSON.stringify(done.dealers, null, 2));
return fail(400, { success: false, errors: done.errors }); if (done.errors.length > 0) {
} return fail(400, { success: false, errors: done.errors });
await dbApiUser.upsertMany(done.dealers, true, ApiUserTypes.DEALER); }
return { success: true, errors: [] as ServerError }; await dbApiUser.upsertMany(done.dealers, true, ApiUserTypes.DEALER);
}, return { success: true, errors: [] as ServerError };
},
} satisfies Actions; } satisfies Actions;

View File

@@ -40,6 +40,7 @@
let refetchDataM = api.apiData.refetchData.createMutation({ let refetchDataM = api.apiData.refetchData.createMutation({
onSuccess: (o) => { onSuccess: (o) => {
console.log(o);
if (!o.success) { if (!o.success) {
for (const each of o.errors) { for (const each of o.errors) {
toast.error(each.message); toast.error(each.message);
@@ -49,6 +50,7 @@
} }
}, },
onError: (e) => { onError: (e) => {
console.log(e);
toast.error(e.message); toast.error(e.message);
}, },
}); });

View File

@@ -19,12 +19,12 @@
let updateDrawFilterM = api.draw.savePresetInfoForDraws.createMutation({ let updateDrawFilterM = api.draw.savePresetInfoForDraws.createMutation({
onSuccess: (d) => { onSuccess: (d) => {
console.log(d); console.log(d);
toast("Saved successfully."); toast("Saved successfully");
}, },
onError: (e) => { onError: (e) => {
console.error(e); console.error(e);
toast( toast(
"An error occurred while fetching data. Try again after a page refresh.", "An error occurred while fetching data. Try again after a page refresh",
); );
}, },
}); });