feat: complete day 7

This commit is contained in:
Ayobami
2025-07-15 16:18:19 +01:00
parent f87c93e85c
commit 10447cd05e
7 changed files with 283 additions and 55 deletions
+8 -4
View File
@@ -24,6 +24,8 @@ async function fetchShopifyCustomers() {
const curlCommand = `curl -i -X GET "${nextUrl}"`;
const { stdout } = await execPromise(curlCommand);
console.log(stdout);
// Separate headers and body
const parts = stdout.split("\r\n\r\n");
const rawHeaders = parts[0];
@@ -70,11 +72,13 @@ async function syncCustomers() {
}
}
syncCustomers();
// run every minute
cron.schedule("* * * * *", () => {
console.log("Running Shopify customer sync...");
syncCustomers();
});
// cron.schedule("* * * * *", () => {
// console.log("Running Shopify customer sync...");
// syncCustomers();
// });
// For manual testing
module.exports = { syncCustomers };
+17 -15
View File
@@ -1,11 +1,12 @@
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var createError = require("http-errors");
var express = require("express");
var path = require("path");
var cookieParser = require("cookie-parser");
var logger = require("morgan");
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var indexRouter = require("./routes/index");
var usersRouter = require("./routes/users");
const userApiRouter = require("./routes/user");
const db = require("./models");
var cors = require("cors");
@@ -13,17 +14,18 @@ var cors = require("cors");
var app = express();
app.set("db", db);
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "jade");
app.use(cors());
app.use(logger('dev'));
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, "public")));
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use("/", indexRouter);
app.use("/users", usersRouter);
app.use("/api/v1/user", userApiRouter);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
@@ -34,11 +36,11 @@ app.use(function (req, res, next) {
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
res.locals.error = req.app.get("env") === "development" ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
res.render("error");
});
module.exports = app;
+48 -34
View File
@@ -1,4 +1,4 @@
'use strict';
"use strict";
/*Powered By: Manaknightdigital Inc. https://manaknightdigital.com/ Year: 2020*/
/**
* Sequelize File
@@ -8,49 +8,63 @@
* @author Ryan Wong
*
*/
const fs = require('fs');
const path = require('path');
let Sequelize = require('sequelize');
const fs = require("fs");
const path = require("path");
let Sequelize = require("sequelize");
const basename = path.basename(__filename);
const { DataTypes } = require('sequelize');
const { DataTypes } = require("sequelize");
const config = {
DB_DATABASE: 'mysql',
DB_USERNAME: 'root',
DB_PASSWORD: 'root',
DB_ADAPTER: 'mysql',
DB_NAME: 'day_1',
DB_HOSTNAME: 'localhost',
DB_DATABASE: "mysql",
DB_USERNAME: "root",
DB_PASSWORD: process.env.DB_PASSWORD || "root",
DB_ADAPTER: "mysql",
DB_NAME: "day_7",
DB_HOSTNAME: "localhost",
DB_PORT: 3306,
};
let db = {};
let sequelize = new Sequelize(config.DB_DATABASE, config.DB_USERNAME, config.DB_PASSWORD, {
dialect: config.DB_ADAPTER,
username: config.DB_USERNAME,
password: config.DB_PASSWORD,
database: config.DB_NAME,
host: config.DB_HOSTNAME,
port: config.DB_PORT,
logging: console.log,
timezone: '-04:00',
pool: {
maxConnections: 1,
minConnections: 0,
maxIdleTime: 100,
},
define: {
timestamps: false,
underscoredAll: true,
underscored: true,
},
});
let sequelize = new Sequelize(
config.DB_NAME,
config.DB_USERNAME,
config.DB_PASSWORD,
{
dialect: config.DB_ADAPTER,
username: config.DB_USERNAME,
password: config.DB_PASSWORD,
database: config.DB_NAME,
host: config.DB_HOSTNAME,
port: config.DB_PORT,
logging: console.log,
timezone: "-04:00",
pool: {
maxConnections: 1,
minConnections: 0,
maxIdleTime: 100,
},
define: {
timestamps: false,
underscoredAll: true,
underscored: true,
},
}
);
// sequelize.sync({ force: true });
sequelize
.sync()
.then(() => {
console.log("All tables synced successfully.");
})
.catch((err) => {
console.error("Failed to sync tables:", err);
});
fs.readdirSync(__dirname)
.filter((file) => {
return file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.js';
return (
file.indexOf(".") !== 0 && file !== basename && file.slice(-3) === ".js"
);
})
.forEach((file) => {
var model = require(path.join(__dirname, file))(sequelize, DataTypes);
@@ -66,4 +80,4 @@ Object.keys(db).forEach((modelName) => {
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
module.exports = db;
+16
View File
@@ -0,0 +1,16 @@
module.exports = (sequelize, DataTypes) => {
const user = sequelize.define("user", {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
wallet_id: DataTypes.STRING,
});
return user;
};
+5 -2
View File
@@ -3,7 +3,8 @@
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www"
"start": "node ./bin/www",
"dev": "node --watch --env-file=.env ./bin/www"
},
"dependencies": {
"cookie-parser": "~1.4.4",
@@ -14,6 +15,8 @@
"jade": "~1.11.0",
"morgan": "~1.9.1",
"mysql2": "^2.3.3",
"sequelize": "^6.15.1"
"node-input-validator": "^4.5.1",
"sequelize": "^6.15.1",
"web3": "^4.16.0"
}
}
+152
View File
@@ -0,0 +1,152 @@
const express = require("express");
const { user } = require("../models");
const {
validateInput,
handleValidationErrorForAPI,
} = require("../services/ValidationService");
const Web3Service = require("../services/Web3Service");
const router = express.Router();
router.get("/", async (req, res, next) => {
try {
const users = await user.findAll();
res.json({ success: true, data: users });
} catch (err) {
next(err);
}
});
const createUserRules = {
name: "required|string",
};
router.post(
"/",
validateInput(createUserRules),
handleValidationErrorForAPI,
async (req, res, next) => {
try {
await user.create(req.body);
res.json({ success: true, message: "User created successfully" });
} catch (err) {
next(err);
}
}
);
// POST /api/v1/user/wallet
router.post(
"/wallet",
validateInput({ id: "required|integer" }),
handleValidationErrorForAPI,
async (req, res) => {
try {
const { id: userId } = req.body;
const u = await user.findByPk(userId);
if (!u) {
return res
.status(404)
.json({ success: false, error: "User not found" });
}
const wallet = Web3Service.createWallet();
await u.update({ wallet_id: wallet.address });
res.json({
success: true,
data: { address: wallet.address, privateKey: wallet.privateKey },
});
} catch (err) {
res.status(500).json({ success: false, error: err.message });
}
}
);
// GET /api/v1/user/sign?private_key=...&message=...
router.get("/sign", (req, res) => {
try {
const { private_key, message } = req.query;
const signed = Web3Service.signMessage(
private_key,
message || "default message"
);
res.json({ success: true, data: signed });
} catch (err) {
res.status(500).json({ success: false, error: err.message });
}
});
// GET /api/v1/user/account?private_key=...
router.get("/account", async (req, res) => {
try {
const { private_key } = req.query;
const account =
Web3Service.web3.eth.accounts.privateKeyToAccount(private_key);
const balance = await Web3Service.getBalance(account.address);
res.json({ success: true, data: { address: account.address, balance } });
} catch (err) {
res.status(500).json({ success: false, error: err.message });
}
});
// GET /api/v1/user/transfer?private_key=...&to_address=...&amount=...
router.get("/transfer", async (req, res) => {
try {
const { private_key, to_address, amount } = req.query;
const tx = await Web3Service.transfer(private_key, to_address, amount);
res.json({ success: true, data: tx });
} catch (err) {
res.status(500).json({ success: false, error: err.message });
}
});
router.get("/:id", async (req, res, next) => {
try {
const u = await user.findByPk(req.params.id);
if (!u) {
return res.status(404).json({ error: "User not found" });
}
res.json({ success: true, data: u });
} catch (err) {
next(err);
}
});
const updateUserRules = {
name: "string",
wallet_id: "string",
};
router.put(
"/:id",
validateInput(updateUserRules),
handleValidationErrorForAPI,
async (req, res, next) => {
try {
const u = await user.findByPk(req.params.id);
if (!u) {
return res.status(404).json({ error: "User not found" });
}
await u.update(req.body);
res.json({ success: true, message: "User updated successfully" });
} catch (err) {
next(err);
}
}
);
router.delete("/:id", async (req, res, next) => {
try {
const u = await user.findByPk(req.params.id);
if (!u) {
return res.status(404).json({ error: "User not found" });
}
await u.destroy();
res.json({ success: true, message: "User deleted successfully" });
} catch (err) {
next(err);
}
});
module.exports = router;
+37
View File
@@ -0,0 +1,37 @@
// services/Web3Service.js
const { Web3 } = require("web3");
const web3 = new Web3(process.env.ALCHEMY_API_URL);
module.exports = {
web3,
createWallet: () => {
return web3.eth.accounts.create();
},
signMessage: (privateKey, message) => {
return web3.eth.accounts.sign(message, privateKey);
},
getBalance: async (address) => {
const balanceWei = await web3.eth.getBalance(address);
return web3.utils.fromWei(balanceWei, "ether");
},
transfer: async (privateKey, to, amount) => {
const account = web3.eth.accounts.privateKeyToAccount(privateKey);
const from = account.address;
const nonce = await web3.eth.getTransactionCount(from, "latest");
const gasPrice = await web3.eth.getGasPrice();
const tx = {
from,
to,
value: web3.utils.toWei(amount, "ether"),
gas: 21000,
gasPrice,
nonce,
};
const signed = await account.signTransaction(tx);
return web3.eth.sendSignedTransaction(signed.rawTransaction);
},
};