added qr_tool and db_tool

This commit is contained in:
cawa 2023-05-29 17:48:25 +03:00
commit 166bee898e
13 changed files with 8633 additions and 0 deletions

15
README.md Normal file
View File

@ -0,0 +1,15 @@
# Comfortech ulitls
Tools for routine operations acceleration
___
### DB Tool
- Dump Database
- Restore Database
### QR Tool
- Create/Update QR codes for userplaces
- Download just created QR code images

3
db_tool/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/dist
/node_modules
/dumps

14
db_tool/README.md Normal file
View File

@ -0,0 +1,14 @@
# Mongo buckup tool
- create backup of database
- restore from local folder
**Backups goes to `dump` folder**
## Setup
`npm i`
## Usage
`npm run start`

163
db_tool/main.js Normal file
View File

@ -0,0 +1,163 @@
import { exec, spawn } from "child_process";
import { readdir } from "fs/promises";
import inquirer from "inquirer";
import moment from "moment";
import { MongoClient } from "mongodb";
const prompt = inquirer.createPromptModule();
const getDirectories = async source =>
(await readdir(source, { withFileTypes: true }))
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name);
async function performBackup(databaseName) {
try {
const timestamp = moment().format("DD.MM.YYYY_HHmmss");
const { backupFolder } = await prompt([
{
type: "input",
name: "backupFolder",
message: "Enter the backup folder path (leave empty for default):",
default: `${databaseName}_${timestamp}`,
},
]);
const folderName = "dumps/" + backupFolder;
const backupCommand = `mongodump --db ${databaseName} --out ${folderName}`;
console.log(`Creating backup of database ${databaseName}...`);
await exec(backupCommand);
console.log(`Backup created successfully in folder ${folderName}.`);
} catch (error) {
console.error("An error occurred during the backup process:", error);
}
}
function performRestore(restoreFolder, uri) {
try {
console.log(`Restoring database from folder ${restoreFolder}...`);
let ls = spawn("mongorestore", ["--uri", uri, "--drop", restoreFolder]);
ls.stdout.on("data", function (data) {
console.log(data.toString());
});
ls.stderr.on("data", function (data) {
console.log(data.toString());
});
ls.on("exit", function (code) {
console.log("child process exited with code " + code.toString());
});
console.log("Database restored successfully.");
} catch (error) {
console.error("An error occurred during the restore process:", error);
}
}
function generateConnectionString({ username, password, host, port }) {
let credentials = "";
if (username && password) {
credentials = `${username}:${password}@`;
}
const uri = `mongodb://${credentials}${host}:${port}`;
return uri;
}
async function main() {
try {
const credentials = await prompt([
{
type: "input",
name: "username",
message: "Enter your MongoDB username:",
},
{
type: "password",
name: "password",
message: "Enter your MongoDB password:",
},
{
type: "input",
name: "host",
message: "Enter the MongoDB host:",
default: "localhost",
},
{
type: "input",
name: "port",
message: "Enter the MongoDB port:",
default: "27017",
},
]);
const uri = generateConnectionString(credentials);
const client = new MongoClient(uri);
await client.connect();
console.log("Connected to MongoDB successfully.");
const { action } = await prompt([
{
type: "list",
name: "action",
message: "Choose an action:",
choices: ["Backup", "Restore"],
},
]);
if (action === "Backup") {
const { databaseName } = await prompt([
{
type: "list",
name: "databaseName",
message: "Choose a database to backup:",
choices: await client
.db()
.admin()
.listDatabases()
.then(({ databases }) => databases.map(({ name }) => name)),
},
]);
await performBackup(databaseName);
} else if (action === "Restore") {
try {
const dirs = await getDirectories("./dumps");
const { restoreFolder } = await prompt([
{
type: "list",
name: "restoreFolder",
message: "Choose the folder to restore from:",
choices: dirs,
},
]);
await performRestore("./dumps/" + restoreFolder, uri);
} catch (err) {
if (err.errno === -2) {
console.log("No 'dumps' dir found");
} else {
throw new Error(err);
}
console.log("Disconnected from MongoDB.");
await client.close();
return;
}
}
await client.close();
console.log("Disconnected from MongoDB.");
} catch (error) {
console.error("An error occurred:", error);
}
}
main();

1928
db_tool/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

18
db_tool/package.json Normal file
View File

@ -0,0 +1,18 @@
{
"name": "backup_mongo",
"version": "1.0.0",
"description": "backup and restore mongo collections",
"main": "main.js",
"scripts": {
"start": "node main",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Cawa",
"license": "ISC",
"type": "module",
"dependencies": {
"inquirer": "^9.2.6",
"moment": "^2.29.4",
"mongodb": "^5.5.0"
}
}

3
qr_tool/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/dist
/node_modules
/out

25
qr_tool/README.md Normal file
View File

@ -0,0 +1,25 @@
# QR codes generator
### Usage
```shell
npm i
node index.js
```
To create qrs you need enter
- Database IP address
- Database external port
- Username
- Password
After that
- Choose **places** to generate QR codes
- Choose **skip** existing qrcodes for selected places or **replace** with new
- Choose **size of image** to save
### Result
Folder `./out` will contain folders with png files.

279
qr_tool/index.js Executable file
View File

@ -0,0 +1,279 @@
import inquirer from "inquirer";
import { MongoClient } from "mongodb";
import QRCode from "qrcode";
import { writeFileSync, mkdirSync } from "fs";
import Jimp from "jimp";
import path from "path";
import fs from "fs";
let url;
let client;
let db;
const dbName = "comfortech";
let host = "176.53.196.42";
let port = "27017";
let pass = "password";
let username = "user";
await inquirer
.prompt([
{
name: "host",
message: "Database host",
default: host,
},
{
name: "port",
message: "Database port",
default: "27017",
},
{
type: "list",
name: "credentials",
message: "Login as a specific user?",
choices: ["No", "Yes"],
},
])
.then(async answers => {
host = answers.host;
port = answers.port;
if (answers.credentials == "Yes") {
await inquirer
.prompt([
{
name: "username",
message: "Username",
default: "user",
},
{
name: "pass",
type: "password",
message: "Password",
},
])
.then(answers => {
username = answers.username;
pass = answers.pass;
});
}
});
async function ask_about_all_places(places) {
const flats_list = places.map(x => {
return `${x.name} ${x._id.toString()}`;
});
return await inquirer
.prompt([
{
name: "all",
message: "Generate QR codes for all places",
type: "confirm",
default: false,
},
])
.then(async answers => {
if (answers.all) {
return {
all: true,
ids: flats_list,
};
} else {
const place_ids = await inquirer
.prompt([
{
name: "flats",
message: "Choose flat numbers",
type: "checkbox",
choices: flats_list,
},
])
.then(async answers => {
// return answers.flats.map(num => num.split(" ")[1]);
return answers.flats;
});
return { all: false, ids: place_ids };
}
});
}
async function ask_size() {
return await inquirer.prompt([
{
name: "size",
type: "number",
message: "Size of a side in px",
default: "354",
},
]);
}
async function ask_to_override_existing(ids) {
ids = ids.map(item => item.split(" ")[1]);
console.log("\n\n", ids, "\n\n");
await db
.createCollection("qr_code")
.then(res => {
console.log("Collection created");
})
.catch(err => {
if (err.code == 48) {
console.info("Collection exists");
} else {
console.error("Error:", err);
}
});
const collection = await db.collection("qr_code");
const override = await inquirer
.prompt([
{
name: "override",
message: "If QR codes exist for chosen places",
type: "list",
choices: ["Skip", "Replace"],
default: "Replace",
},
])
.then(answer => {
return answer.override == "Skip" ? false : true;
});
if (override) {
const res = await collection.deleteMany({
place_id: {
$in: [...ids],
},
});
} else {
let res = collection.find({
place_id: {
$in: [...ids],
},
});
const existing_qrs = await res.toArray();
const exclude_places = existing_qrs.map(el => el.place_id);
console.log(`Skiped ${exclude_places.length}/${ids.length} places (QR code exists)`);
exclude_places.forEach(place_id => {
const index = ids.indexOf(place_id);
if (index !== -1) {
ids.splice(index, 1);
}
});
console.log(ids.length, "places left");
}
if (ids.length == 0) return [];
let qrcode_ids = [];
let docs = [];
await ids.forEach(async place_id => {
docs.push({
place_id,
one_time: false,
});
});
const res = await collection
.insertMany(docs)
.then(res => {
return res;
})
.catch(err => {
console.error(err);
});
for (const [key, value] of Object.entries(res.insertedIds)) {
qrcode_ids.push(value.toString());
}
return qrcode_ids;
}
function getAvailableName(fullpath) {
let dir = path.dirname(fullpath);
let base = path.basename(fullpath);
for (let i = 0; fs.existsSync(fullpath); i++) {
let items = base.split(".");
fullpath = dir + "/" + items[0] + "_" + i + "." + items[1];
}
return fullpath;
}
// Connection URL
async function main() {
url = `mongodb://${username ? username + ":" + pass + "@" : ""}${host}:${port}`;
client = new MongoClient(url);
// Use connect method to connect to the server
await client.connect();
db = client.db(dbName);
console.info("Connected successfully");
const place_col = db.collection("place");
const places = place_col.find({ place_type: "flat" });
console.info(await place_col.countDocuments({ place_type: "flat" }), "places found");
const flats = await ask_about_all_places(await places.toArray());
console.info(`Generate QR codes for ${flats.ids.length} places`);
console.info(`Places: ${flats.ids} `);
const qrcode_ids = await ask_to_override_existing(flats.ids);
console.log(qrcode_ids.length, "QR codes generated in data base");
await client.close();
const qr_size = parseInt((await ask_size()).size);
console.log(qr_size, "px");
const folder = new Date().valueOf();
mkdirSync("out/" + folder, { recursive: true });
qrcode_ids.forEach(async qr => {
QRCode.toDataURL(qr, {
errorCorrectionLevel: "H",
scale: 3,
margin: 5,
width: 512,
color: { light: "#fafafa", dark: "#121212" },
})
.then(url => {
const base64Data = url.replace(/^data:image\/png;base64,/, "");
const index = qrcode_ids.indexOf(qr);
let fileName = `./out/${folder}/${flats.ids[index].split(" ")[0]}.png`;
fileName = getAvailableName(fileName);
writeFileSync(`${fileName}`, base64Data, "base64");
const imageCaption = "KB. " + flats.ids[index].split(" ")[0];
let loadedImage;
Jimp.read(fileName)
.then(function (image) {
loadedImage = image;
var fontpath = path.join(process.cwd(), "opensans/open_sans_32.fnt");
return Jimp.loadFont(fontpath);
})
.then(function (font) {
loadedImage.print(font, 204, 12, imageCaption).write(fileName);
const isHorizontal = loadedImage.getWidth() > loadedImage.getHeight();
const ratio = isHorizontal
? loadedImage.getWidth() / loadedImage.getHeight()
: loadedImage.getHeight() / loadedImage.getWidth();
const width = qr_size; // set the width you want
const height = isHorizontal ? width / ratio : width * ratio;
return loadedImage.resize(width, height, Jimp.RESIZE_BICUBIC).quality(60).write(fileName);
})
.catch(function (err) {
console.error(err);
});
})
.catch(err => {
console.error(err);
});
});
}
await main();
console.log("Exited");

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,99 @@
info face="Open Sans" size=-32 bold=0 italic=0 charset="" unicode=1 stretchH=100 smooth=0 aa=1 padding=0,0,0,0 spacing=0,0 outline=0
common lineHeight=44 base=35 scaleW=256 scaleH=128 pages=1 packed=0 alphaChnl=0 redChnl=4 greenChnl=4 blueChnl=4
page id=0 file="open-sans-32.png"
chars count=95
char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=0 xadvance=8 page=0 chnl=15
char id=33 x=248 y=29 width=4 height=24 xoffset=2 yoffset=11 xadvance=8 page=0 chnl=15
char id=34 x=59 y=72 width=9 height=9 xoffset=2 yoffset=11 xadvance=13 page=0 chnl=15
char id=35 x=46 y=24 width=19 height=24 xoffset=1 yoffset=11 xadvance=21 page=0 chnl=15
char id=36 x=100 y=74 width=15 height=27 xoffset=2 yoffset=10 xadvance=19 page=0 chnl=15
char id=37 x=0 y=81 width=24 height=24 xoffset=2 yoffset=11 xadvance=27 page=0 chnl=15
char id=38 x=24 y=81 width=22 height=24 xoffset=2 yoffset=11 xadvance=24 page=0 chnl=15
char id=39 x=73 y=72 width=3 height=9 xoffset=2 yoffset=11 xadvance=7 page=0 chnl=15
char id=40 x=228 y=0 width=8 height=29 xoffset=1 yoffset=11 xadvance=9 page=0 chnl=15
char id=41 x=236 y=0 width=8 height=29 xoffset=1 yoffset=11 xadvance=10 page=0 chnl=15
char id=42 x=212 y=15 width=16 height=15 xoffset=1 yoffset=10 xadvance=18 page=0 chnl=15
char id=43 x=211 y=35 width=15 height=16 xoffset=2 yoffset=15 xadvance=19 page=0 chnl=15
char id=44 x=68 y=72 width=5 height=8 xoffset=1 yoffset=31 xadvance=8 page=0 chnl=15
char id=45 x=28 y=75 width=8 height=3 xoffset=1 yoffset=24 xadvance=10 page=0 chnl=15
char id=46 x=36 y=75 width=4 height=4 xoffset=2 yoffset=31 xadvance=8 page=0 chnl=15
char id=47 x=176 y=24 width=12 height=24 xoffset=0 yoffset=11 xadvance=12 page=0 chnl=15
char id=48 x=123 y=0 width=15 height=24 xoffset=2 yoffset=11 xadvance=18 page=0 chnl=15
char id=49 x=229 y=48 width=9 height=24 xoffset=3 yoffset=11 xadvance=18 page=0 chnl=15
char id=50 x=132 y=48 width=15 height=24 xoffset=2 yoffset=11 xadvance=18 page=0 chnl=15
char id=51 x=133 y=24 width=15 height=24 xoffset=1 yoffset=11 xadvance=18 page=0 chnl=15
char id=52 x=83 y=76 width=17 height=24 xoffset=1 yoffset=11 xadvance=18 page=0 chnl=15
char id=53 x=138 y=0 width=15 height=24 xoffset=2 yoffset=11 xadvance=18 page=0 chnl=15
char id=54 x=130 y=97 width=15 height=24 xoffset=2 yoffset=11 xadvance=18 page=0 chnl=15
char id=55 x=145 y=72 width=15 height=24 xoffset=1 yoffset=11 xadvance=18 page=0 chnl=15
char id=56 x=147 y=48 width=15 height=24 xoffset=2 yoffset=11 xadvance=18 page=0 chnl=15
char id=57 x=148 y=24 width=15 height=24 xoffset=2 yoffset=11 xadvance=18 page=0 chnl=15
char id=58 x=217 y=89 width=4 height=18 xoffset=2 yoffset=17 xadvance=8 page=0 chnl=15
char id=59 x=223 y=69 width=6 height=22 xoffset=0 yoffset=17 xadvance=8 page=0 chnl=15
char id=60 x=195 y=72 width=15 height=17 xoffset=2 yoffset=15 xadvance=19 page=0 chnl=15
char id=61 x=44 y=72 width=15 height=9 xoffset=2 yoffset=19 xadvance=19 page=0 chnl=15
char id=62 x=197 y=18 width=15 height=17 xoffset=2 yoffset=15 xadvance=19 page=0 chnl=15
char id=63 x=162 y=48 width=13 height=24 xoffset=0 yoffset=11 xadvance=14 page=0 chnl=15
char id=64 x=0 y=24 width=25 height=27 xoffset=2 yoffset=11 xadvance=29 page=0 chnl=15
char id=65 x=25 y=24 width=21 height=24 xoffset=0 yoffset=11 xadvance=20 page=0 chnl=15
char id=66 x=116 y=48 width=16 height=24 xoffset=3 yoffset=11 xadvance=20 page=0 chnl=15
char id=67 x=65 y=24 width=18 height=24 xoffset=2 yoffset=11 xadvance=20 page=0 chnl=15
char id=68 x=70 y=0 width=18 height=24 xoffset=3 yoffset=11 xadvance=23 page=0 chnl=15
char id=69 x=163 y=24 width=13 height=24 xoffset=3 yoffset=11 xadvance=17 page=0 chnl=15
char id=70 x=168 y=0 width=13 height=24 xoffset=3 yoffset=11 xadvance=16 page=0 chnl=15
char id=71 x=51 y=0 width=19 height=24 xoffset=2 yoffset=11 xadvance=23 page=0 chnl=15
char id=72 x=99 y=50 width=17 height=24 xoffset=3 yoffset=11 xadvance=23 page=0 chnl=15
char id=73 x=248 y=53 width=3 height=24 xoffset=3 yoffset=11 xadvance=9 page=0 chnl=15
char id=74 x=188 y=24 width=9 height=30 xoffset=-3 yoffset=11 xadvance=9 page=0 chnl=15
char id=75 x=100 y=24 width=17 height=24 xoffset=3 yoffset=11 xadvance=20 page=0 chnl=15
char id=76 x=175 y=48 width=13 height=24 xoffset=3 yoffset=11 xadvance=17 page=0 chnl=15
char id=77 x=21 y=51 width=23 height=24 xoffset=3 yoffset=11 xadvance=29 page=0 chnl=15
char id=78 x=65 y=81 width=18 height=24 xoffset=3 yoffset=11 xadvance=24 page=0 chnl=15
char id=79 x=30 y=0 width=21 height=24 xoffset=2 yoffset=11 xadvance=25 page=0 chnl=15
char id=80 x=153 y=0 width=15 height=24 xoffset=3 yoffset=11 xadvance=19 page=0 chnl=15
char id=81 x=0 y=51 width=21 height=30 xoffset=2 yoffset=11 xadvance=25 page=0 chnl=15
char id=82 x=106 y=0 width=17 height=24 xoffset=3 yoffset=11 xadvance=20 page=0 chnl=15
char id=83 x=145 y=96 width=15 height=24 xoffset=1 yoffset=11 xadvance=18 page=0 chnl=15
char id=84 x=83 y=100 width=17 height=24 xoffset=1 yoffset=11 xadvance=19 page=0 chnl=15
char id=85 x=88 y=0 width=18 height=24 xoffset=3 yoffset=11 xadvance=24 page=0 chnl=15
char id=86 x=44 y=48 width=20 height=24 xoffset=0 yoffset=11 xadvance=19 page=0 chnl=15
char id=87 x=0 y=0 width=30 height=24 xoffset=0 yoffset=11 xadvance=30 page=0 chnl=15
char id=88 x=46 y=81 width=19 height=24 xoffset=0 yoffset=11 xadvance=18 page=0 chnl=15
char id=89 x=64 y=48 width=19 height=24 xoffset=0 yoffset=11 xadvance=18 page=0 chnl=15
char id=90 x=117 y=24 width=16 height=24 xoffset=1 yoffset=11 xadvance=18 page=0 chnl=15
char id=91 x=210 y=89 width=7 height=29 xoffset=3 yoffset=11 xadvance=11 page=0 chnl=15
char id=92 x=181 y=0 width=12 height=24 xoffset=0 yoffset=11 xadvance=12 page=0 chnl=15
char id=93 x=244 y=0 width=8 height=29 xoffset=0 yoffset=11 xadvance=10 page=0 chnl=15
char id=94 x=208 y=0 width=17 height=15 xoffset=1 yoffset=11 xadvance=18 page=0 chnl=15
char id=95 x=15 y=123 width=14 height=3 xoffset=0 yoffset=37 xadvance=14 page=0 chnl=15
char id=96 x=21 y=75 width=7 height=6 xoffset=1 yoffset=9 xadvance=9 page=0 chnl=15
char id=97 x=197 y=35 width=14 height=18 xoffset=1 yoffset=17 xadvance=17 page=0 chnl=15
char id=98 x=115 y=100 width=15 height=25 xoffset=3 yoffset=10 xadvance=20 page=0 chnl=15
char id=99 x=210 y=71 width=13 height=18 xoffset=2 yoffset=17 xadvance=15 page=0 chnl=15
char id=100 x=130 y=72 width=15 height=25 xoffset=2 yoffset=10 xadvance=20 page=0 chnl=15
char id=101 x=188 y=54 width=15 height=18 xoffset=2 yoffset=17 xadvance=18 page=0 chnl=15
char id=102 x=174 y=101 width=12 height=26 xoffset=1 yoffset=9 xadvance=12 page=0 chnl=15
char id=103 x=83 y=50 width=16 height=26 xoffset=1 yoffset=17 xadvance=18 page=0 chnl=15
char id=104 x=160 y=72 width=14 height=25 xoffset=3 yoffset=10 xadvance=20 page=0 chnl=15
char id=105 x=251 y=58 width=3 height=24 xoffset=3 yoffset=11 xadvance=8 page=0 chnl=15
char id=106 x=202 y=89 width=8 height=32 xoffset=-2 yoffset=11 xadvance=8 page=0 chnl=15
char id=107 x=160 y=97 width=14 height=25 xoffset=3 yoffset=10 xadvance=17 page=0 chnl=15
char id=108 x=252 y=33 width=3 height=25 xoffset=3 yoffset=10 xadvance=8 page=0 chnl=15
char id=109 x=0 y=105 width=25 height=18 xoffset=3 yoffset=17 xadvance=30 page=0 chnl=15
char id=110 x=203 y=53 width=14 height=18 xoffset=3 yoffset=17 xadvance=20 page=0 chnl=15
char id=111 x=67 y=105 width=16 height=18 xoffset=2 yoffset=17 xadvance=19 page=0 chnl=15
char id=112 x=100 y=101 width=15 height=26 xoffset=3 yoffset=17 xadvance=20 page=0 chnl=15
char id=113 x=115 y=74 width=15 height=26 xoffset=2 yoffset=17 xadvance=20 page=0 chnl=15
char id=114 x=238 y=51 width=10 height=18 xoffset=3 yoffset=17 xadvance=13 page=0 chnl=15
char id=115 x=217 y=51 width=12 height=18 xoffset=2 yoffset=17 xadvance=15 page=0 chnl=15
char id=116 x=238 y=29 width=10 height=22 xoffset=1 yoffset=13 xadvance=12 page=0 chnl=15
char id=117 x=193 y=0 width=15 height=18 xoffset=3 yoffset=17 xadvance=20 page=0 chnl=15
char id=118 x=186 y=101 width=16 height=18 xoffset=0 yoffset=17 xadvance=16 page=0 chnl=15
char id=119 x=25 y=105 width=25 height=18 xoffset=0 yoffset=17 xadvance=25 page=0 chnl=15
char id=120 x=50 y=105 width=17 height=18 xoffset=0 yoffset=17 xadvance=17 page=0 chnl=15
char id=121 x=83 y=24 width=17 height=26 xoffset=-1 yoffset=17 xadvance=16 page=0 chnl=15
char id=122 x=226 y=30 width=12 height=18 xoffset=1 yoffset=17 xadvance=14 page=0 chnl=15
char id=123 x=185 y=72 width=10 height=29 xoffset=1 yoffset=11 xadvance=12 page=0 chnl=15
char id=124 x=252 y=0 width=3 height=33 xoffset=8 yoffset=10 xadvance=18 page=0 chnl=15
char id=125 x=174 y=72 width=11 height=29 xoffset=1 yoffset=11 xadvance=12 page=0 chnl=15
char id=126 x=0 y=123 width=15 height=5 xoffset=2 yoffset=20 xadvance=19 page=0 chnl=15

6064
qr_tool/package-lock.json generated Executable file

File diff suppressed because it is too large Load Diff

22
qr_tool/package.json Executable file
View File

@ -0,0 +1,22 @@
{
"name": "qr_code_generator",
"version": "1.0.0",
"description": "Genetares QR codes for places",
"main": "index.js",
"scripts": {
"start": "node --experimental-modules index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"type": "module",
"author": "Alexander Evsikov",
"license": "ISC",
"dependencies": {
"easyqrcodejs": "^4.4.13",
"inquirer": "^9.1.4",
"jimp": "^0.16.2",
"jsdom": "^20.0.3",
"mongodb": "^4.12.1",
"qr-image": "^3.2.0",
"qrcode": "^1.5.1"
}
}