const userController = require("./controllers/userController"); const { User,Counter, generateBookingId,resetCounter,generateCustomerId,ProfilePicture} = require('./models/User') //const tanksController = require("./controllers/tanksController"); const tankersController = require("./controllers/tankersController.js"); const createConnectionController = require("./controllers/createConnectionController"); const cors = require("cors"); const swagger = require("./config/swagger"); const rawBody = require('raw-body') const uuidv4 = require("uuid").v4; const fastify = require("fastify")({ logger: true, //disableRequestLogging: true, genReqId(req) { // you get access to the req here if you need it - must be a synchronous function return uuidv4(); }, }); // const Fastify = require("fastify"); // const Fastify = require("fastify"); // const server = Fastify({ // logger: true, // // ajv: { plugins: [ajvPlugin] }, // genReqId(req) { // // you get access to the req here if you need it - must be a synchronous function // return uuidv4(); // }, // }); // fastify.register(View).ready((err) => { // if (err) console.error(err); // console.log(fastify.config.PORT); // or fastify[options.confKey] // // output: { PORT: 3000 } // engine: { // ejs: require('ejs'), // }, // root: join(__dirname, 'views/html'), // }); const now = () => Date.now(); const fastifyEnv = require("fastify-env"); const schema = { type: "object", required: ["PORT"], properties: { PORT: { type: "string", default: 3000, }, APIVERSION: { type: "string", default: "1.0.0", }, }, }; const options = { confKey: "config", // optional, default: 'config' schema: schema, // data: data // optional, default: process.env }; fastify.register(fastifyEnv, options).ready((err) => { if (err) console.error(err); console.log(fastify.config.PORT); // or fastify[options.confKey] // output: { PORT: 3000 } fastify.decorate("conf", { port: fastify.config.PORT, APIVERSION: fastify.config.APIVERSION, }); }); const apiversion = "1.0.0"; const path = require("path"); // Using static content for swagger documentation. Generated swagger UI is not user friendly. fastify.register(require("fastify-static"), { root: path.join(__dirname, "api-docs"), prefix: "/api-docs", // optional: default '/' }); fastify.register(require("fastify-swagger"), swagger.options); const customJwtAuth = require("./customAuthJwt"); fastify.register(customJwtAuth); //login route - accept user credentials and send a token with role . "user" role is required to use the app. // support login using application/x-www-form-urlencoded so users can login via a web form in addition to api // fastify.register(require("fastify-formbody")); // fastify.register(require('fastify-multipart')) // fastify.register(require("fastify-cors"), { // // put your options here // origin: [ // new RegExp("http://localhost"), // new RegExp("http://simply-backoffice.true2air.com"), // new RegExp("http://localhost:3000"), // ], // credentials: true, // optionsSuccessStatus: 200, // }); fastify.register((fastify, opts, done) => { fastify.addContentTypeParser( "application/json", { parseAs: "buffer" }, function (_req, body, done) { try { done(null, body) } catch (error) { error.statusCode = 400 done(error, undefined) } } ) done(null) }) fastify.register(require('point-of-view'), { engine: { nunjucks: require('nunjucks') }, root: path.join(__dirname, "views"), includeViewExtension: true, }); // * This is for login user as a simply user * fastify.post("/api/login", { schema: { description: "This is for Login User", tags: ["Login"], summary: "This is for User Login", body: { type: "object", required: ["phone", "password"], properties: { phone: { type: "string" }, password: { type: "string" }, }, }, }, async handler(req, reply) { loginObject = await userController.loginUser(req); if (loginObject.same) { const phoneVerified = loginObject.user.phoneVerified; const oneTimePasswordSetFlag = loginObject.user.oneTimePasswordSetFlag; console.log( "oneTimePasswordSetFlag is ......", oneTimePasswordSetFlag, typeof oneTimePasswordSetFlag, typeof phoneVerified ); if (!phoneVerified) { reply.send({ simplydata: { error: false, phoneVerified: false, phone: loginObject.user.phone, oneTimePasswordSetFlag: oneTimePasswordSetFlag, message: "Please Verify your phone number", }, }); } else if (oneTimePasswordSetFlag) { reply.send({ simplydata: { error: false, phoneVerified: phoneVerified, phone: loginObject.user.phone, oneTimePasswordSetFlag: true, message: "Password must be reset", }, }); } else { const token = fastify.jwt.sign( { username: loginObject.user.username, userId: loginObject.user._id, roles: loginObject.user.profile.role, }, //expiresIn: expressed in seconds or a string describing a time span zeit/ms. Eg: 60, "2 days", "10h", "7d". //A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), //otherwise milliseconds unit is used by default ("120" is equal to "120ms"). { expiresIn: "30d" } ); var arr = loginObject.user.profile.role; var arrayToString = JSON.stringify(Object.assign({}, arr)); // convert array to string var stringToJsonObject = JSON.parse(arrayToString); // convert string to json object var c_id = loginObject.user.customerId var profilePicture = await ProfilePicture.findOne({ customerId:c_id}); if (!profilePicture) { reply.send({ simplydata: { error: false, apiversion: fastify.config.APIVERSION, access_token: token, email: loginObject.user.emails, phone: loginObject.user.phone, customerId: loginObject.user.customerId, username: loginObject.user.username, address1: loginObject.user.profile.address1, address2: loginObject.user.profile.address2, phoneVerified: loginObject.user.phoneVerified, oneTimePasswordSetFlag: loginObject.user.oneTimePasswordSetFlag, latitude: loginObject.user.latitude, longitude: loginObject.user.longitude, type: loginObject.user.profile.role, fcmId: loginObject.user.fcmId, typeasobj: stringToJsonObject, }, }); }if (profilePicture) { reply.send({ simplydata: { error: false, apiversion: fastify.config.APIVERSION, access_token: token, picture:profilePicture.picture, email: loginObject.user.emails, phone: loginObject.user.phone, customerId: loginObject.user.customerId, username: loginObject.user.username, address1: loginObject.user.profile.address1, address2: loginObject.user.profile.address2, phoneVerified: loginObject.user.phoneVerified, oneTimePasswordSetFlag: loginObject.user.oneTimePasswordSetFlag, latitude: loginObject.user.latitude, longitude: loginObject.user.longitude, type: loginObject.user.profile.role, typeasobj: stringToJsonObject, }, }); } // console.log({ // username: loginObject.user.username, // roles: loginObject.user.profile.role, // rolesasobj: stringToJsonObject, // }); // console.log("sending token \n"); // console.log(token); } } else { error = { simplydata: { error: true, code: 400, message: "Invalid UserId , Password supplied", }, }; reply.send(error); } }, }); fastify.get("/api/reset_token/:customerId", { schema: { description: "This is for Reset Token", tags: ["Login"], summary: "This is for Reset Token", params: { type: "object", properties: { customerId: { type: "string", description: "customerId", }, }, }, }, async handler(req, reply) { try { const customerId = req.params.customerId const get_user = await userController.getSingleUser(req); const token = fastify.jwt.sign( { customerId: get_user.customerId, userId: get_user._id, roles: get_user.profile.role, }, { expiresIn: "30d" } ); reply.send({ access_token: token, customerId: get_user.customerId }); } catch (err) { console.log(err); error = { simplydata: { error: true, code: 400, message: "Reset Token failed", }, }; reply.status(401).send(error); } }, }); fastify.get('/testtemp', (req, reply) => { reply.view('layouts/main', {}); }); // const multipart = require('fastify-multipart'); // fastify.register(multipart); //fastify-auth plugin is required so we can define routes in seperate files and verify jwt supplied in preHandlers for each request. //const multer = require("fastify-multer"); fastify.register(require("fastify-auth")); const dbConnection = require("./config/config"); fastify.register(dbConnection); //fastify.register(multer.contentParser); const { Schema } = require("mongoose"); // fastify.register(dbConnection); fastify.register(require("./routes/usersRoute")); fastify.register(require("./routes/tanksRoute")); fastify.register(require("./routes/createConnectionsRoute")); fastify.register(require("./routes/tankersRoute.js")); fastify.register(require("./routes/supplierRoute")); fastify.register(require("./routes/supplierOrdersRoutes")); fastify.register(require("./routes/friendRequestRoute")); fastify.register(require("./routes/adminRoute")); // Testing route allows for retrieving a user by phone so one can see what is the phone verification code sent for a given user's phone // Also allows deletion of a user with a given phone number fastify.register(require("./routes/forTestingRoute")); const fs = require('fs'); const {Storage} = require('@google-cloud/storage'); const { Supplier, profilePictureSupplier } = require("./models/supplier"); const multer = require('fastify-multer'); fastify.register(require('fastify-formbody')); // fastify.register(multer.contentParser); // const multipart = require('fastify-multipart'); // fastify.register(multipart); const gc = new Storage({ keyFilename : path.join(__dirname, "../src/arminta-tank-keyFile.json"), projectId : 'arminta-tank' }) const storage = new Storage({ keyFilename : path.join(__dirname, "../src/arminta-tank-keyFile.json"), projectId : 'arminta-tank' }); // console.log(storage) // const cloudinary = require('cloudinary').v2; // const FormData = require('form-data'); // const mv = require('mv'); // cloudinary.config({ // cloud_name: 'dalqpseol', // api_key: '121595628244491', // api_secret: 'jnuny_0fMYovQS0eyvIVXQTl4RY' // }); // Register fastify-file-upload plugin fastify.register(require('fastify-multipart')); // fastify.post('/upload', async (request, reply) => { // try { // const data = await request.file(); // // Generate a unique file name // const fileName = `${data.filename}`; // const filePath = `${fileName}`; // // Move the file to a temporary location // const writeStream = fs.createWriteStream(filePath); // data.file.pipe(writeStream); // writeStream.on('close', () => { // // Upload the image to Cloudinary // cloudinary.uploader.upload(filePath, (error, result) => { // if (error) { // reply.code(500).send({ error: 'Failed to upload file to Cloudinary' }); // } else { // // Get the public URL of the uploaded image // const publicUrl = result.secure_url; // // Remove the temporary file // fs.unlinkSync(filePath); // // Return the public URL // reply.send({ url: publicUrl }); // } // }); // }); // writeStream.on('error', (err) => { // reply.code(500).send({ error: 'Failed to move file' }); // }); // } catch (err) { // reply.code(500).send({ error: 'An error occurred' }); // } // }); // fastify.post('/upload/:supplierId', async (request, reply) => { // try { // const supplierId = request.params.supplierId; // const data = await request.file(); // // Generate a unique file name // const fileName = `${data.filename}`; // const filePath = `${fileName}`; // // Move the file to a temporary location // const writeStream = fs.createWriteStream(filePath); // data.file.pipe(writeStream); // writeStream.on('close', () => { // // Upload the image to Cloudinary // cloudinary.uploader.upload(filePath, (error, result) => { // if (error) { // reply.code(500).send({ error: 'Failed to upload file to Cloudinary' }); // } else { // // Get the public URL of the uploaded image // const publicUrl = result.secure_url; // // Remove the temporary file // fs.unlinkSync(filePath); // // Store the URL in the database // // Assuming you have a database connection and a ProfilePictureSupplier model // profilePictureSupplier.findOneAndUpdate( // { supplierId }, // { picture: publicUrl }, // { new: true, upsert: true }, // (error, picture) => { // if (error) { // reply.code(500).send({ error: 'Failed to update database' }); // } else { // // Return the public URL // reply.send({ picture: publicUrl }); // } // } // ); // } // }); // }); // writeStream.on('error', (err) => { // reply.code(500).send({ error: 'Failed to move file' }); // }); // } catch (err) { // reply.code(500).send({ error: 'An error occurred' }); // } // }); fastify.post('/api/uploads/:supplierId', async (request, reply) => { try { const supplierId = request.params.supplierId; const data = await request.file(); // Generate a unique file name const fileName = `${data.filename}`; // Define the destination bucket and file path const bucketName = 'arminta_profile_pictures'; const filePath = `${fileName}`; // Create a write stream to the destination file in the bucket const writeStream = storage.bucket(bucketName).file(filePath).createWriteStream(); // Pipe the file data to the write stream data.file.pipe(writeStream); writeStream.on('finish', async () => { try { // Make the uploaded file publicly accessible await storage.bucket(bucketName).file(filePath).makePublic(); const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; profilePictureSupplier.findOneAndUpdate( { supplierId }, { picture: publicUrl }, { new: true, upsert: true }, (error, picture) => { if (error) { reply.code(500).send({ error: 'Failed to update database' }); } else { // Return the public URL reply.send({ picture: publicUrl }); } } ); } catch (error) { reply.code(500).send({ error: 'Failed to make file public' }); } }); writeStream.on('error', (err) => { reply.code(500).send({ error: 'Failed to move file' }); }); } catch (err) { reply.code(500).send({ error: 'An error occurred' }); } }); fastify.post('/api/uploads-user/:customerId', async (request, reply) => { try { const customerId = request.params.customerId; const data = await request.file(); // Generate a unique file name const fileName = `${data.filename}`; // Define the destination bucket and file path const bucketName = 'arminta_profile_pictures'; const filePath = `arminta_user_profiles/${fileName}`; // Create a write stream to the destination file in the bucket const writeStream = storage.bucket(bucketName).file(filePath).createWriteStream(); // Pipe the file data to the write stream data.file.pipe(writeStream); writeStream.on('finish', async () => { try { // Make the uploaded file publicly accessible await storage.bucket(bucketName).file(filePath).makePublic(); const publicUrl = `https://storage.googleapis.com/${bucketName}/${filePath}`; ProfilePicture.findOneAndUpdate( { customerId }, { picture: publicUrl }, { new: true, upsert: true }, (error, picture) => { if (error) { reply.code(500).send({ error: 'Failed to update database' }); } else { // Return the public URL reply.send({ picture: publicUrl }); } } ); } catch (error) { reply.code(500).send({ error: 'Failed to make file public' }); } }); writeStream.on('error', (err) => { reply.code(500).send({ error: 'Failed to move file' }); }); } catch (err) { reply.code(500).send({ error: 'An error occurred' }); } }); // Run the server! const start = async () => { try { await fastify.listen(3000, "0.0.0.0"); fastify.log.info(`listening on ${fastify.server.address().port}`); fastify.log.info(`server listening on ${fastify.config}`); } catch (err) { fastify.log.error(err); process.exit(1); } }; start();