From 83c27845f6202cbd6d26ac07175227b8cbbcef3c Mon Sep 17 00:00:00 2001 From: Sumit Dhanania Date: Wed, 17 Mar 2021 04:08:32 +0530 Subject: [PATCH 01/13] Get userStocks --- controllers/stocksController.js | 22 +++++++++- docs/swaggerDefinition.js | 23 +++++++++++ models/stocks.js | 73 ++++++++++++++++++++++++++++++++- models/trading.js | 43 ++++++++++++++----- public/apiSchema.json | 2 +- routes/users.js | 25 +++++++++++ 6 files changed, 174 insertions(+), 14 deletions(-) diff --git a/controllers/stocksController.js b/controllers/stocksController.js index 314fa5520..da567e7fd 100644 --- a/controllers/stocksController.js +++ b/controllers/stocksController.js @@ -37,8 +37,28 @@ const fetchStocks = async (req, res) => { return res.boom.badImplementation('An internal server error occurred') } } +/** + * Fetches all the stocks of the user + * + * @param req {Object} - Express request object + * @param res {Object} - Express response object + */ +const getUserStocks = async (req, res, next) => { + try { + const { id: userId } = req.userData + const userStocks = await stocks.fetchUserStocks(userId) + return res.json({ + message: 'User stocks returned successfully!', + userStocks + }) + } catch (err) { + logger.error(`Error while getting user stocks ${err}`) + return res.boom.badImplementation('An internal server error occurred') + } +} module.exports = { addNewStock, - fetchStocks + fetchStocks, + getUserStocks } diff --git a/docs/swaggerDefinition.js b/docs/swaggerDefinition.js index d061bef2e..4fea98f79 100644 --- a/docs/swaggerDefinition.js +++ b/docs/swaggerDefinition.js @@ -498,6 +498,29 @@ const swaggerOptions = { } } }, + userStocks: { + type: 'object', + properties: { + userId: { + type: 'string' + }, + stockId: { + type: 'string' + }, + stockName: { + type: 'string' + }, + quantity: { + type: 'number' + }, + orderValue: { + type: 'number' + }, + initialStockValue: { + type: 'number' + } + } + }, auctions: { type: 'object', properties: { diff --git a/models/stocks.js b/models/stocks.js index 54f9235f2..281cab02c 100644 --- a/models/stocks.js +++ b/models/stocks.js @@ -1,5 +1,7 @@ const firestore = require('../utils/firestore') const stocksModel = firestore.collection('stocks') +const userStocksModel = firestore.collection('user-stocks') + /** * Adds Stocks * @@ -38,7 +40,76 @@ const fetchStocks = async () => { } } +/** + * Fetches the user stocks + * @return {Promise} + */ +const fetchUserStocks = async (userId, stockId = null) => { + try { + userStocksModel.where('userId', '==', userId) + + if (stockId) { + userStocksModel.where('stockId', '==', stockId) + } + const { docs } = await userStocksModel.get() + const [userStocks] = docs + if (userStocks) { + return { id: userStocks.id, ...userStocks.data() } + } + return {} + } catch (err) { + logger.error('Error retrieving user stocks', err) + throw err + } +} + +/** + * Create user stocks + * @return {Promise} + */ +const createUserStock = async (userId, stockData) => { + try { + const userStocks = { + userId, + ...stockData + } + const { id } = await userStocksModel.add(userStocks) + return { + id + } + } catch (err) { + logger.error('Error creating user stocks', err) + throw err + } +} + +/** + * Update Users Stocks + * @return {Promise} + */ +const updateUserStocks = async (userId, stockData) => { + try { + const userStocks = await fetchUserStocks(userId, stockData.stockId) + if (!userStocks.id) { + await createUserStock(userId, stockData) + return true + } + + const userStocksRef = userStocksModel.doc(userStocks.id) + const res = await userStocksRef.update(stockData) + if (res) { + return true + } + return false + } catch (err) { + logger.error('Error updating users stocks', err) + throw err + } +} + module.exports = { addStock, - fetchStocks + fetchStocks, + fetchUserStocks, + updateUserStocks } diff --git a/models/trading.js b/models/trading.js index 8e4daa5fc..db32a42e4 100644 --- a/models/trading.js +++ b/models/trading.js @@ -3,6 +3,7 @@ const stocksModel = firestore.collection('stocks') const transactionsModel = firestore.collection('transactions') const tradeLogsModel = firestore.collection('trade-logs') const { fetchWallet, updateWallet } = require('../models/wallets') +const { fetchUserStocks, updateUserStocks } = require('../models/stocks') const INSUFFICIENT_FUNDS = 'Trade was not successful due to insufficient funds' @@ -26,16 +27,17 @@ const getUpdatedPrice = (stockPrice) => { const trade = async (tradeData) => { // ! TODO - update as per curreny type, currently only using dinero try { - const { stockId, quantity, tradeType, totalPrice, userId } = tradeData + const { stockId, stockName, quantity, tradeType, totalPrice, userId } = tradeData const stockCollection = await stocksModel.doc(stockId).get() const stockData = stockCollection.data() let userBalance = 0 let quantityToUpdate = 0 - let stockPriceToBeUpdated = stockData.price - let orderValue = 0 - let qtyUserCanPurchase = 0 + let qtyUserCanPurchase = quantity + let userStocksQty = 0 + let initialStockValue = stockData.price const { currencies } = await fetchWallet(userId) + const userStocks = await fetchUserStocks(userId, stockId) const updatedCurrencyData = {} if (!currencies) { @@ -45,9 +47,9 @@ const trade = async (tradeData) => { switch (tradeType) { case 'SELL': { quantityToUpdate = quantity + stockData.quantity - userBalance = quantity * stockData.price - updatedCurrencyData.dinero = userBalance + currencies.dinero - stockPriceToBeUpdated = getUpdatedPrice(stockData.price) + userBalance = (quantity * stockData.price) + currencies.dinero + updatedCurrencyData.dinero = userBalance + userStocksQty = userStocks.quantity - quantity break } case 'BUY': { @@ -55,11 +57,17 @@ const trade = async (tradeData) => { if (qtyUserCanPurchase <= 0 || totalPrice > currencies.dinero) { return { canUserTrade: false, errorMessage: INSUFFICIENT_FUNDS } } - orderValue = qtyUserCanPurchase * stockData.price quantityToUpdate = stockData.quantity - qtyUserCanPurchase - userBalance = currencies.dinero - orderValue + userBalance = currencies.dinero - (qtyUserCanPurchase * stockData.price) updatedCurrencyData.dinero = userBalance - stockPriceToBeUpdated = getUpdatedPrice(stockData.price) + userStocksQty = qtyUserCanPurchase + + initialStockValue = stockData.price + + if (userStocks.id) { + userStocksQty = userStocks.quantity + qtyUserCanPurchase + initialStockValue = userStocks.initialStockValue + } break } default: { @@ -67,12 +75,25 @@ const trade = async (tradeData) => { } } + const orderValue = qtyUserCanPurchase * stockData.price + const stockPriceToBeUpdated = getUpdatedPrice(stockData.price) + const updatedStockData = { ...stockData, quantity: quantityToUpdate, price: stockPriceToBeUpdated } + // Update user stocks + + await updateUserStocks(userId, { + stockId, + stockName, + quantity: userStocksQty, + orderValue: userStocksQty * stockData.price, + initialStockValue + }) + // Transaction Log const { id } = await tradeLogsModel.add({ @@ -94,7 +115,7 @@ const trade = async (tradeData) => { // update user wallet - updateWallet(userId, { + await updateWallet(userId, { ...currencies, ...updatedCurrencyData }) diff --git a/public/apiSchema.json b/public/apiSchema.json index 51c445657..ea22dc1da 100644 --- a/public/apiSchema.json +++ b/public/apiSchema.json @@ -1 +1 @@ -{"openapi":"3.0.1","info":{"version":"1.0.0","title":"RDS API documentation","description":"This is documentation for Real Dev Squad's API. Find out more about Real dev squad at [http://realdevsquad.com](http://realdevsquad.com)","contact":{"name":"Real Dev Squad","url":"http://realdevsquad.com"}},"tags":[{"name":"Healthcheck","description":"API for health check in the system"},{"name":"Authentication","description":"Authentication routes"}],"servers":[{"url":"http://localhost:3000","description":"Local server URL"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"healthCheck":{"type":"object","properties":{"uptime":{"type":"number"}}},"tasks":{"type":"object","properties":{"title":{"type":"string"},"purpose":{"type":"string"},"featureUrl":{"type":"string"},"type":{"type":"string"},"links":{"type":"array","items":{"link1":{"type":"string"}}},"endsOn":{"type":"string"},"startedOn":{"type":"string"},"status":{"type":"string"},"ownerId":{"type":"string"},"percentCompleted":{"type":"number"},"dependsOn":{"type":"array","items":{"taskid":{"type":"string"}}},"participants":{"type":"array","items":{"userid":{"type":"string"}}},"completionAward":{"type":"object","properties":{"gold":{"type":"number"},"silver":{"type":"number"},"bronze":{"type":"number"}}},"lossRate":{"type":"object","properties":{"gold":{"type":"number"},"silver":{"type":"number"},"bronze":{"type":"number"}}},"isNoteworthy":{"type":"boolean"}}},"contributions":{"type":"object","properties":{"noteworthy":{"type":"array","items":{"type":"object","properties":{"task":{"type":"object","properties":{"title":{"type":"string"},"purpose":{"type":"string"},"featureUrl":{"type":"string"},"endsOn":{"type":"string"},"startedOn":{"type":"string"},"status":{"type":"string"},"dependsOn":{"type":"array","items":{"type":"string"}},"participants":{"type":"array","items":{"type":"object","properties":{"firstname":{"type":"string"},"lastname":{"type":"string"},"img":{"type":"string"},"username":{"type":"string"}}}},"isNoteworthy":{"type":"boolean"}}},"prList":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"url":{"type":"string"},"state":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"raisedBy":{"type":"string"}}}}}}},"all":{"type":"array","items":{"type":"object","properties":{"task":{"type":"object","properties":{"title":{"type":"string"},"purpose":{"type":"string"},"featureUrl":{"type":"string"},"endsOn":{"type":"string"},"startedOn":{"type":"string"},"status":{"type":"string"},"dependsOn":{"type":"array","items":{"type":"string"}},"participants":{"type":"array","items":{"type":"object","properties":{"firstname":{"type":"string"},"lastname":{"type":"string"},"img":{"type":"string"},"username":{"type":"string"}}}},"isNoteworthy":{"type":"boolean"}}},"prList":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"url":{"type":"string"},"state":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"raisedBy":{"type":"string"}}}}}}}}},"challenges":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"level":{"type":"string"},"start_date":{"type":"string"},"end_date":{"type":"string"},"is_active":{"type":"boolean"},"participants":{"type":"array","items":[]}}},"pullRequests":{"type":"object","properties":{"title":{"type":"string"},"url":{"type":"string"},"state":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"readyForReview":{"type":"boolean"},"labels":{"type":"array","items":[]},"assignees":{"type":"array","items":[]}}},"users":{"type":"object","properties":{"username":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"yoe":{"type":"number"},"company":{"type":"string"},"designation":{"type":"string"},"img":{"type":"string"},"github_display_name":{"type":"string"},"github_id":{"type":"string"},"linkedin_id":{"type":"string"},"twitter_id":{"type":"string"},"instagram_id":{"type":"string"},"site":{"type":"string"},"isMember":{"type":"boolean"},"tokens":{"type":"object"}}},"badges":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"imgUrl":{"type":"string"},"users":{"type":"array","items":{"type":"string"}}}},"userAvailable":{"type":"object","properties":{"isUsernameAvailable":{"type":"boolean"}}},"stocks":{"type":"object","properties":{"name":{"type":"string"},"price":{"type":"number"},"quantity":{"type":"number"}}},"trading":{"type":"object","properties":{"stockId":{"type":"string"},"tradeType":{"type":"string"},"stockName":{"type":"string"},"quantity":{"type":"number"},"listedPrice":{"type":"number"},"totalPrice":{"type":"number"}}},"tradingSuccess":{"type":"object","properties":{"userBalance":{"type":"number"}}},"auctions":{"type":"object","properties":{"id":{"type":"string"},"seller":{"type":"string"},"item_type":{"type":"string"},"quantity":{"type":"number"},"highest_bid":{"type":"number"},"highest_bidder":{"type":"number"},"start_time":{"type":"number"},"end_time":{"type":"number"},"bidders_and_bids":{"type":"array"}}},"errors":{"unAuthorized":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}},"notFound":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}},"forbidden":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}},"badImplementation":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}},"serverUnavailable":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"paths":{"/auctions/:id":{"get":{"summary":"Fetches auction details for given auctionId","tags":["Auctions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Auction details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/auctions"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/auctions":{"get":{"summary":"Get all the active (ongoing) auctions","tags":["Auctions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"All ongoing auctions","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Auctions returned successfully!"},"auctions":{"type":"array","items":{"$ref":"#/components/schemas/auctions"}}}}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}},"post":{"summary":"Creates a new auction","tags":["Auctions"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"New auction","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Auction created successfully!"},"id":{"type":"string"}}}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/auctions/bid/:id":{"post":{"summary":"Makes a new bid given auctionId","tags":["Auctions"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"New bid","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Successfully placed bid!"},"id":{"type":"string"}}}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/auth/github/callback":{"get":{"summary":"Authenticates the user using the GitHub Oauth 2.0. Redirects to the UI on successful login","tags":["Authentication"],"parameters":[{"in":"query","name":"code","required":true,"type":"string","description":"Temporary code returned by GitHub Oauth"}],"responses":{"302":{"description":"Redirects to the UI on successful login","headers":{"Cookie":{"type":"string","description":"Cookie containing authentication token"},"Location":{"type":"string","description":"Redirection URL"}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}}}}},"/badges":{"get":{"summary":"Get all the badges in system.","tags":["Badges"],"responses":{"200":{"description":"Badge details","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Badges returned successfully!"},"badges":{"type":"array","items":{"$ref":"#/components/schemas/badges"}}}}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}}},"/challenges":{"get":{"summary":"Used to get all the challenges","tags":["Challenges"],"responses":{"200":{"description":"Return challenges","content":{"application/json":{"schema":{"$ref":"#/components/schemas/challenges"}}}},"404":{"description":"No challenges found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}},"post":{"summary":"Post new challenge","tags":["Challenges"],"responses":{"200":{"description":"Post challenge","content":{"application/json":{"schema":{"$ref":"#/components/schemas/challenges"}}}},"404":{"description":"Unable to add challenge","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}}},"/challenges/subscribe":{"post":{"summary":"Subscribe user to challenge","tags":["Challenges"],"responses":{"200":{"description":"Subscribed sucessfully","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"User has subscribed to challenge"}}}}}},"404":{"description":"Unable to add challenge","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}}},"/contributions/{username}":{"get":{"summary":"Used to get all the contributions of user","tags":["Contributions"],"responses":{"200":{"description":"Return contributions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/contributions"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/healthcheck":{"get":{"summary":"Use to check health status of the server.","tags":["Healthcheck"],"responses":{"200":{"description":"Server uptime status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/healthCheck"}}}}}}},"/healthcheck/v2":{"get":{"summary":"Sample route to test authentication middleware.","tags":["Healthcheck"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Server uptime status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/healthCheck"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}}}}},"/members":{"get":{"summary":"Gets details of all the Real Dev Squad members","tags":["Members"],"responses":{"200":{"description":"Details of all the RDS members","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/members/idle":{"get":{"summary":"Gets details of idle members of the Real Dev Squad","tags":["Members"],"responses":{"200":{"description":"Details of inactive/idle members of the RDS members","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/pullrequests/open":{"get":{"summary":"Latest 10 Pull Requests in Real Dev Squad","tags":["Pull Requests"],"responses":{"200":{"description":"Pull Requests","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Open PRs"},"pullRequests":{"type":"array","items":{"$ref":"#/components/schemas/pullRequests"}}}}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/pullrequests/stale":{"get":{"summary":"All open Pull Requests in Real Dev Squad","tags":["Pull Requests"],"responses":{"200":{"description":"Pull Requests","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Stale PRs"},"pullRequests":{"type":"array","items":{"$ref":"#/components/schemas/pullRequests"}}}}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/pullrequests/user/:username":{"get":{"summary":"Pull Requests by a user in Real Dev Squad","tags":["Pull Requests"],"responses":{"200":{"description":"Pull Requests","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Pull requests returned successfully!"},"pullRequests":{"type":"array","items":{"$ref":"#/components/schemas/pullRequests"}}}}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/stocks":{"get":{"summary":"Used to get all the stocks","tags":["Stocks"],"responses":{"200":{"description":"returns stocks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/stocks"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}},"post":{"summary":"Used to create new stock","tags":["Stocks"],"requestBody":{"description":"Stock data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/stocks"}}}},"responses":{"200":{"description":"returns newly created stock","content":{"application/json":{"schema":{"$ref":"#/components/schemas/stocks"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/tasks":{"get":{"summary":"Used to get all the tasks","tags":["Tasks"],"responses":{"200":{"description":"returns tasks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}},"post":{"summary":"Used to create new task","tags":["Tasks"],"requestBody":{"description":"Task data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"responses":{"200":{"description":"returns newly created task","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}},"patch":{"summary":"Used to update task details","tags":["Tasks"],"requestBody":{"description":"Task data to be updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"responses":{"204":{"description":"no content"},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/tasks/self":{"get":{"summary":"Use to get all the tasks of the logged in user","tags":["Tasks"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"returns all tasks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/trade/stock/new/self":{"post":{"summary":"Used for new trading request","tags":["Trading"],"security":[{"bearerAuth":[]}],"requestBody":{"description":"Trading details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/trading"}}}},"responses":{"200":{"description":"Successful trading details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tradingSuccess"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/users/self":{"patch":{"summary":"Use to update the user data.","requestBody":{"description":"User data to be updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content"},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}},"get":{"summary":"Use to get self details.","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/users":{"get":{"summary":"Get all the users in system.","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User details","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Users returned successfully!"},"users":{"type":"array","items":{"$ref":"#/components/schemas/users"}}}}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}}},"/users/isUsernameAvailable/:username":{"get":{"summary":"check user exists or not","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User Availability","content":{"application/json":{"schema":{"$ref":"#/components/schemas/userAvailable"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/users/:username":{"get":{"summary":"Get the details of user with provided id.","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/wallet/":{"get":{"summary":"Gets the user wallet details","tags":["wallet"],"responses":{"200":{"description":"Return wallet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/wallet"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}}}} \ No newline at end of file +{"openapi":"3.0.1","info":{"version":"1.0.0","title":"RDS API documentation","description":"This is documentation for Real Dev Squad's API. Find out more about Real dev squad at [http://realdevsquad.com](http://realdevsquad.com)","contact":{"name":"Real Dev Squad","url":"http://realdevsquad.com"}},"tags":[{"name":"Healthcheck","description":"API for health check in the system"},{"name":"Authentication","description":"Authentication routes"}],"servers":[{"url":"http://localhost:3000","description":"Local server URL"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"healthCheck":{"type":"object","properties":{"uptime":{"type":"number"}}},"tasks":{"type":"object","properties":{"title":{"type":"string"},"purpose":{"type":"string"},"featureUrl":{"type":"string"},"type":{"type":"string"},"links":{"type":"array","items":{"link1":{"type":"string"}}},"endsOn":{"type":"string"},"startedOn":{"type":"string"},"status":{"type":"string"},"ownerId":{"type":"string"},"percentCompleted":{"type":"number"},"dependsOn":{"type":"array","items":{"taskid":{"type":"string"}}},"participants":{"type":"array","items":{"userid":{"type":"string"}}},"completionAward":{"type":"object","properties":{"gold":{"type":"number"},"silver":{"type":"number"},"bronze":{"type":"number"}}},"lossRate":{"type":"object","properties":{"gold":{"type":"number"},"silver":{"type":"number"},"bronze":{"type":"number"}}},"isNoteworthy":{"type":"boolean"}}},"contributions":{"type":"object","properties":{"noteworthy":{"type":"array","items":{"type":"object","properties":{"task":{"type":"object","properties":{"title":{"type":"string"},"purpose":{"type":"string"},"featureUrl":{"type":"string"},"endsOn":{"type":"string"},"startedOn":{"type":"string"},"status":{"type":"string"},"dependsOn":{"type":"array","items":{"type":"string"}},"participants":{"type":"array","items":{"type":"object","properties":{"firstname":{"type":"string"},"lastname":{"type":"string"},"img":{"type":"string"},"username":{"type":"string"}}}},"isNoteworthy":{"type":"boolean"}}},"prList":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"url":{"type":"string"},"state":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"raisedBy":{"type":"string"}}}}}}},"all":{"type":"array","items":{"type":"object","properties":{"task":{"type":"object","properties":{"title":{"type":"string"},"purpose":{"type":"string"},"featureUrl":{"type":"string"},"endsOn":{"type":"string"},"startedOn":{"type":"string"},"status":{"type":"string"},"dependsOn":{"type":"array","items":{"type":"string"}},"participants":{"type":"array","items":{"type":"object","properties":{"firstname":{"type":"string"},"lastname":{"type":"string"},"img":{"type":"string"},"username":{"type":"string"}}}},"isNoteworthy":{"type":"boolean"}}},"prList":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"url":{"type":"string"},"state":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"raisedBy":{"type":"string"}}}}}}}}},"challenges":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"level":{"type":"string"},"start_date":{"type":"string"},"end_date":{"type":"string"},"is_active":{"type":"boolean"},"participants":{"type":"array","items":[]}}},"pullRequests":{"type":"object","properties":{"title":{"type":"string"},"url":{"type":"string"},"state":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"readyForReview":{"type":"boolean"},"labels":{"type":"array","items":[]},"assignees":{"type":"array","items":[]}}},"users":{"type":"object","properties":{"username":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"yoe":{"type":"number"},"company":{"type":"string"},"designation":{"type":"string"},"img":{"type":"string"},"github_display_name":{"type":"string"},"github_id":{"type":"string"},"linkedin_id":{"type":"string"},"twitter_id":{"type":"string"},"instagram_id":{"type":"string"},"site":{"type":"string"},"isMember":{"type":"boolean"},"tokens":{"type":"object"}}},"badges":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"imgUrl":{"type":"string"},"users":{"type":"array","items":{"type":"string"}}}},"userAvailable":{"type":"object","properties":{"isUsernameAvailable":{"type":"boolean"}}},"stocks":{"type":"object","properties":{"name":{"type":"string"},"price":{"type":"number"},"quantity":{"type":"number"}}},"trading":{"type":"object","properties":{"stockId":{"type":"string"},"tradeType":{"type":"string"},"stockName":{"type":"string"},"quantity":{"type":"number"},"listedPrice":{"type":"number"},"totalPrice":{"type":"number"}}},"tradingSuccess":{"type":"object","properties":{"userBalance":{"type":"number"}}},"userStocks":{"type":"object","properties":{"userId":{"type":"string"},"stockId":{"type":"string"},"stockName":{"type":"string"},"quantity":{"type":"number"},"orderValue":{"type":"number"},"initialStockValue":{"type":"number"}}},"auctions":{"type":"object","properties":{"id":{"type":"string"},"seller":{"type":"string"},"item_type":{"type":"string"},"quantity":{"type":"number"},"highest_bid":{"type":"number"},"highest_bidder":{"type":"number"},"start_time":{"type":"number"},"end_time":{"type":"number"},"bidders_and_bids":{"type":"array"}}},"errors":{"unAuthorized":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}},"notFound":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}},"forbidden":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}},"badImplementation":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}},"serverUnavailable":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"paths":{"/auctions/:id":{"get":{"summary":"Fetches auction details for given auctionId","tags":["Auctions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Auction details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/auctions"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/auctions":{"get":{"summary":"Get all the active (ongoing) auctions","tags":["Auctions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"All ongoing auctions","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Auctions returned successfully!"},"auctions":{"type":"array","items":{"$ref":"#/components/schemas/auctions"}}}}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}},"post":{"summary":"Creates a new auction","tags":["Auctions"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"New auction","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Auction created successfully!"},"id":{"type":"string"}}}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/auctions/bid/:id":{"post":{"summary":"Makes a new bid given auctionId","tags":["Auctions"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"New bid","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Successfully placed bid!"},"id":{"type":"string"}}}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/auth/github/callback":{"get":{"summary":"Authenticates the user using the GitHub Oauth 2.0. Redirects to the UI on successful login","tags":["Authentication"],"parameters":[{"in":"query","name":"code","required":true,"type":"string","description":"Temporary code returned by GitHub Oauth"}],"responses":{"302":{"description":"Redirects to the UI on successful login","headers":{"Cookie":{"type":"string","description":"Cookie containing authentication token"},"Location":{"type":"string","description":"Redirection URL"}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}}}}},"/badges":{"get":{"summary":"Get all the badges in system.","tags":["Badges"],"responses":{"200":{"description":"Badge details","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Badges returned successfully!"},"badges":{"type":"array","items":{"$ref":"#/components/schemas/badges"}}}}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}}},"/challenges":{"get":{"summary":"Used to get all the challenges","tags":["Challenges"],"responses":{"200":{"description":"Return challenges","content":{"application/json":{"schema":{"$ref":"#/components/schemas/challenges"}}}},"404":{"description":"No challenges found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}},"post":{"summary":"Post new challenge","tags":["Challenges"],"responses":{"200":{"description":"Post challenge","content":{"application/json":{"schema":{"$ref":"#/components/schemas/challenges"}}}},"404":{"description":"Unable to add challenge","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}}},"/challenges/subscribe":{"post":{"summary":"Subscribe user to challenge","tags":["Challenges"],"responses":{"200":{"description":"Subscribed sucessfully","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"User has subscribed to challenge"}}}}}},"404":{"description":"Unable to add challenge","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}}},"/contributions/{username}":{"get":{"summary":"Used to get all the contributions of user","tags":["Contributions"],"responses":{"200":{"description":"Return contributions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/contributions"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/healthcheck":{"get":{"summary":"Use to check health status of the server.","tags":["Healthcheck"],"responses":{"200":{"description":"Server uptime status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/healthCheck"}}}}}}},"/healthcheck/v2":{"get":{"summary":"Sample route to test authentication middleware.","tags":["Healthcheck"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Server uptime status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/healthCheck"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}}}}},"/members":{"get":{"summary":"Gets details of all the Real Dev Squad members","tags":["Members"],"responses":{"200":{"description":"Details of all the RDS members","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/members/idle":{"get":{"summary":"Gets details of idle members of the Real Dev Squad","tags":["Members"],"responses":{"200":{"description":"Details of inactive/idle members of the RDS members","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/pullrequests/open":{"get":{"summary":"Latest 10 Pull Requests in Real Dev Squad","tags":["Pull Requests"],"responses":{"200":{"description":"Pull Requests","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Open PRs"},"pullRequests":{"type":"array","items":{"$ref":"#/components/schemas/pullRequests"}}}}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/pullrequests/stale":{"get":{"summary":"All open Pull Requests in Real Dev Squad","tags":["Pull Requests"],"responses":{"200":{"description":"Pull Requests","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Stale PRs"},"pullRequests":{"type":"array","items":{"$ref":"#/components/schemas/pullRequests"}}}}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/pullrequests/user/:username":{"get":{"summary":"Pull Requests by a user in Real Dev Squad","tags":["Pull Requests"],"responses":{"200":{"description":"Pull Requests","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Pull requests returned successfully!"},"pullRequests":{"type":"array","items":{"$ref":"#/components/schemas/pullRequests"}}}}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/stocks":{"get":{"summary":"Used to get all the stocks","tags":["Stocks"],"responses":{"200":{"description":"returns stocks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/stocks"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}},"post":{"summary":"Used to create new stock","tags":["Stocks"],"requestBody":{"description":"Stock data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/stocks"}}}},"responses":{"200":{"description":"returns newly created stock","content":{"application/json":{"schema":{"$ref":"#/components/schemas/stocks"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/tasks":{"get":{"summary":"Used to get all the tasks","tags":["Tasks"],"responses":{"200":{"description":"returns tasks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}},"post":{"summary":"Used to create new task","tags":["Tasks"],"requestBody":{"description":"Task data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"responses":{"200":{"description":"returns newly created task","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}},"patch":{"summary":"Used to update task details","tags":["Tasks"],"requestBody":{"description":"Task data to be updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"responses":{"204":{"description":"no content"},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/tasks/self":{"get":{"summary":"Use to get all the tasks of the logged in user","tags":["Tasks"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"returns all tasks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/trade/stock/new/self":{"post":{"summary":"Used for new trading request","tags":["Trading"],"security":[{"bearerAuth":[]}],"requestBody":{"description":"Trading details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/trading"}}}},"responses":{"200":{"description":"Successful trading details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tradingSuccess"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/users/self":{"patch":{"summary":"Use to update the user data.","requestBody":{"description":"User data to be updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content"},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}},"get":{"summary":"Use to get self details.","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/users":{"get":{"summary":"Get all the users in system.","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User details","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Users returned successfully!"},"users":{"type":"array","items":{"$ref":"#/components/schemas/users"}}}}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}}},"/users/isUsernameAvailable/:username":{"get":{"summary":"check user exists or not","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User Availability","content":{"application/json":{"schema":{"$ref":"#/components/schemas/userAvailable"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/users/:username":{"get":{"summary":"Get the details of user with provided id.","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/stocks/self":{"get":{"summary":"Used to get all the stocks","tags":["Users Stocks"],"responses":{"200":{"description":"returns stocks of the user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/userStocks"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/wallet/":{"get":{"summary":"Gets the user wallet details","tags":["wallet"],"responses":{"200":{"description":"Return wallet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/wallet"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}}}} \ No newline at end of file diff --git a/routes/users.js b/routes/users.js index 24320e11c..cd9f523d7 100644 --- a/routes/users.js +++ b/routes/users.js @@ -3,6 +3,7 @@ const router = express.Router() const authenticate = require('../middlewares/authenticate') const usersController = require('../controllers/usersController') const userValidator = require('../middlewares/validators/user') +const { getUserStocks } = require('../controllers/stocksController') /** * @swagger @@ -209,4 +210,28 @@ router.get('/isUsernameAvailable/:username', authenticate, usersController.getUs */ router.get('/:username', usersController.getUser) +/** + * @swagger + * /stocks/self: + * get: + * summary: Used to get all the stocks + * tags: + * - Users Stocks + * responses: + * 200: + * description: returns stocks of the user + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/userStocks' + * 500: + * description: badImplementation + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/errors/badImplementation' + */ + +router.get('/stocks/self', authenticate, getUserStocks) + module.exports = router From bf65de13bde253e6607fe2b549291254aa35de5b Mon Sep 17 00:00:00 2001 From: Sumit Dhanania Date: Thu, 18 Mar 2021 02:28:13 +0530 Subject: [PATCH 02/13] Fix issue for updating user stocks --- models/stocks.js | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/models/stocks.js b/models/stocks.js index 281cab02c..7a546ce8f 100644 --- a/models/stocks.js +++ b/models/stocks.js @@ -46,17 +46,25 @@ const fetchStocks = async () => { */ const fetchUserStocks = async (userId, stockId = null) => { try { - userStocksModel.where('userId', '==', userId) - + let userStocksRef = '' if (stockId) { - userStocksModel.where('stockId', '==', stockId) - } - const { docs } = await userStocksModel.get() - const [userStocks] = docs - if (userStocks) { - return { id: userStocks.id, ...userStocks.data() } + userStocksRef = await userStocksModel.where('userId', '==', userId).where('stockId', '==', stockId).get() + const [userStocks] = userStocksRef.docs + if (userStocks) { + return { id: userStocks.id, ...userStocks.data() } + } + return {} } - return {} + + userStocksRef = await userStocksModel.where('userId', '==', userId).get() + const userStocks = [] + userStocksRef.forEach((stock) => { + userStocks.push({ + id: stock.id, + ...stock.data() + }) + }) + return userStocks } catch (err) { logger.error('Error retrieving user stocks', err) throw err From d0ce9caaad09518d1f91df1a02006a20da98f9af Mon Sep 17 00:00:00 2001 From: Sumit Dhanania Date: Sat, 27 Mar 2021 02:00:26 +0530 Subject: [PATCH 03/13] Add validation to check if user can sell stocks --- models/trading.js | 8 ++++++-- public/apiSchema.json | 2 +- routes/stocks.js | 26 +++++++++++++++++++++++++- routes/users.js | 25 ------------------------- 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/models/trading.js b/models/trading.js index db32a42e4..6564c4def 100644 --- a/models/trading.js +++ b/models/trading.js @@ -6,6 +6,7 @@ const { fetchWallet, updateWallet } = require('../models/wallets') const { fetchUserStocks, updateUserStocks } = require('../models/stocks') const INSUFFICIENT_FUNDS = 'Trade was not successful due to insufficient funds' +const INSUFFICIENT_QUANTITIES = 'Trade was not successful because you do not have enough quantity' /** * Updates the stock Price @@ -46,9 +47,12 @@ const trade = async (tradeData) => { switch (tradeType) { case 'SELL': { + if (!userStocks.id || userStocks.quantity < quantity) { + return { canUserTrade: false, errorMessage: INSUFFICIENT_QUANTITIES } + } + quantityToUpdate = quantity + stockData.quantity userBalance = (quantity * stockData.price) + currencies.dinero - updatedCurrencyData.dinero = userBalance userStocksQty = userStocks.quantity - quantity break } @@ -59,7 +63,6 @@ const trade = async (tradeData) => { } quantityToUpdate = stockData.quantity - qtyUserCanPurchase userBalance = currencies.dinero - (qtyUserCanPurchase * stockData.price) - updatedCurrencyData.dinero = userBalance userStocksQty = qtyUserCanPurchase initialStockValue = stockData.price @@ -77,6 +80,7 @@ const trade = async (tradeData) => { const orderValue = qtyUserCanPurchase * stockData.price const stockPriceToBeUpdated = getUpdatedPrice(stockData.price) + updatedCurrencyData.dinero = userBalance const updatedStockData = { ...stockData, diff --git a/public/apiSchema.json b/public/apiSchema.json index b31bc163e..16085ce22 100644 --- a/public/apiSchema.json +++ b/public/apiSchema.json @@ -1 +1 @@ -{"openapi":"3.0.1","info":{"version":"1.0.0","title":"RDS API documentation","description":"This is documentation for Real Dev Squad's API. Find out more about Real dev squad at [http://realdevsquad.com](http://realdevsquad.com)","contact":{"name":"Real Dev Squad","url":"http://realdevsquad.com"}},"tags":[{"name":"Healthcheck","description":"API for health check in the system"},{"name":"Authentication","description":"Authentication routes"}],"servers":[{"url":"http://localhost:3000","description":"Local server URL"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"healthCheck":{"type":"object","properties":{"uptime":{"type":"number"}}},"tasks":{"type":"object","properties":{"title":{"type":"string"},"purpose":{"type":"string"},"featureUrl":{"type":"string"},"type":{"type":"string"},"links":{"type":"array","items":{"link1":{"type":"string"}}},"endsOn":{"type":"string"},"startedOn":{"type":"string"},"status":{"type":"string"},"ownerId":{"type":"string"},"percentCompleted":{"type":"number"},"dependsOn":{"type":"array","items":{"taskid":{"type":"string"}}},"participants":{"type":"array","items":{"userid":{"type":"string"}}},"completionAward":{"type":"object","properties":{"gold":{"type":"number"},"silver":{"type":"number"},"bronze":{"type":"number"}}},"lossRate":{"type":"object","properties":{"gold":{"type":"number"},"silver":{"type":"number"},"bronze":{"type":"number"}}},"isNoteworthy":{"type":"boolean"}}},"contributions":{"type":"object","properties":{"noteworthy":{"type":"array","items":{"type":"object","properties":{"task":{"type":"object","properties":{"title":{"type":"string"},"purpose":{"type":"string"},"featureUrl":{"type":"string"},"endsOn":{"type":"string"},"startedOn":{"type":"string"},"status":{"type":"string"},"dependsOn":{"type":"array","items":{"type":"string"}},"participants":{"type":"array","items":{"type":"object","properties":{"firstname":{"type":"string"},"lastname":{"type":"string"},"img":{"type":"string"},"username":{"type":"string"}}}},"isNoteworthy":{"type":"boolean"}}},"prList":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"url":{"type":"string"},"state":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"raisedBy":{"type":"string"}}}}}}},"all":{"type":"array","items":{"type":"object","properties":{"task":{"type":"object","properties":{"title":{"type":"string"},"purpose":{"type":"string"},"featureUrl":{"type":"string"},"endsOn":{"type":"string"},"startedOn":{"type":"string"},"status":{"type":"string"},"dependsOn":{"type":"array","items":{"type":"string"}},"participants":{"type":"array","items":{"type":"object","properties":{"firstname":{"type":"string"},"lastname":{"type":"string"},"img":{"type":"string"},"username":{"type":"string"}}}},"isNoteworthy":{"type":"boolean"}}},"prList":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"url":{"type":"string"},"state":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"raisedBy":{"type":"string"}}}}}}}}},"challenges":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"level":{"type":"string"},"start_date":{"type":"string"},"end_date":{"type":"string"},"is_active":{"type":"boolean"},"participants":{"type":"array","items":[]}}},"pullRequests":{"type":"object","properties":{"title":{"type":"string"},"url":{"type":"string"},"state":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"readyForReview":{"type":"boolean"},"labels":{"type":"array","items":[]},"assignees":{"type":"array","items":[]}}},"users":{"type":"object","properties":{"username":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"yoe":{"type":"number"},"company":{"type":"string"},"designation":{"type":"string"},"img":{"type":"string"},"github_display_name":{"type":"string"},"github_id":{"type":"string"},"linkedin_id":{"type":"string"},"twitter_id":{"type":"string"},"instagram_id":{"type":"string"},"site":{"type":"string"},"isMember":{"type":"boolean"},"tokens":{"type":"object"}}},"badges":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"imgUrl":{"type":"string"},"users":{"type":"array","items":{"type":"string"}}}},"userAvailable":{"type":"object","properties":{"isUsernameAvailable":{"type":"boolean"}}},"stocks":{"type":"object","properties":{"name":{"type":"string"},"price":{"type":"number"},"quantity":{"type":"number"}}},"trading":{"type":"object","properties":{"stockId":{"type":"string"},"tradeType":{"type":"string"},"stockName":{"type":"string"},"quantity":{"type":"number"},"listedPrice":{"type":"number"},"totalPrice":{"type":"number"}}},"tradingSuccess":{"type":"object","properties":{"userBalance":{"type":"number"}}},"auctions":{"type":"object","properties":{"id":{"type":"string"},"seller":{"type":"string"},"item_type":{"type":"string"},"quantity":{"type":"number"},"highest_bid":{"type":"number"},"highest_bidder":{"type":"number"},"start_time":{"type":"number"},"end_time":{"type":"number"},"bidders_and_bids":{"type":"array"}}},"errors":{"unAuthorized":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}},"notFound":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}},"forbidden":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}},"badImplementation":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}},"serverUnavailable":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"paths":{"/auctions/:id":{"get":{"summary":"Fetches auction details for given auctionId","tags":["Auctions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Auction details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/auctions"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/auctions":{"get":{"summary":"Get all the active (ongoing) auctions","tags":["Auctions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"All ongoing auctions","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Auctions returned successfully!"},"auctions":{"type":"array","items":{"$ref":"#/components/schemas/auctions"}}}}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}},"post":{"summary":"Creates a new auction","tags":["Auctions"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"New auction","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Auction created successfully!"},"id":{"type":"string"}}}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/auctions/bid/:id":{"post":{"summary":"Makes a new bid given auctionId","tags":["Auctions"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"New bid","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Successfully placed bid!"},"id":{"type":"string"}}}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/auth/github/callback":{"get":{"summary":"Authenticates the user using the GitHub Oauth 2.0. Redirects to the UI on successful login","tags":["Authentication"],"parameters":[{"in":"query","name":"code","required":true,"type":"string","description":"Temporary code returned by GitHub Oauth"}],"responses":{"302":{"description":"Redirects to the UI on successful login","headers":{"Cookie":{"type":"string","description":"Cookie containing authentication token"},"Location":{"type":"string","description":"Redirection URL"}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}}}}},"/badges":{"get":{"summary":"Get all the badges in system.","tags":["Badges"],"responses":{"200":{"description":"Badge details","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Badges returned successfully!"},"badges":{"type":"array","items":{"$ref":"#/components/schemas/badges"}}}}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}}},"/challenges":{"get":{"summary":"Used to get all the challenges","tags":["Challenges"],"responses":{"200":{"description":"Return challenges","content":{"application/json":{"schema":{"$ref":"#/components/schemas/challenges"}}}},"404":{"description":"No challenges found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}},"post":{"summary":"Post new challenge","tags":["Challenges"],"responses":{"200":{"description":"Post challenge","content":{"application/json":{"schema":{"$ref":"#/components/schemas/challenges"}}}},"404":{"description":"Unable to add challenge","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}}},"/challenges/subscribe":{"post":{"summary":"Subscribe user to challenge","tags":["Challenges"],"responses":{"200":{"description":"Subscribed sucessfully","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"User has subscribed to challenge"}}}}}},"404":{"description":"Unable to add challenge","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}}},"/contributions/{username}":{"get":{"summary":"Used to get all the contributions of user","tags":["Contributions"],"responses":{"200":{"description":"Return contributions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/contributions"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/healthcheck":{"get":{"summary":"Use to check health status of the server.","tags":["Healthcheck"],"responses":{"200":{"description":"Server uptime status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/healthCheck"}}}}}}},"/healthcheck/v2":{"get":{"summary":"Sample route to test authentication middleware.","tags":["Healthcheck"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Server uptime status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/healthCheck"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}}}}},"/members":{"get":{"summary":"Gets details of all the Real Dev Squad members","tags":["Members"],"responses":{"200":{"description":"Details of all the RDS members","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/members/idle":{"get":{"summary":"Gets details of idle members of the Real Dev Squad","tags":["Members"],"responses":{"200":{"description":"Details of inactive/idle members of the RDS members","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/pullrequests/open":{"get":{"summary":"Latest 10 Pull Requests in Real Dev Squad","tags":["Pull Requests"],"responses":{"200":{"description":"Pull Requests","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Open PRs"},"pullRequests":{"type":"array","items":{"$ref":"#/components/schemas/pullRequests"}}}}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/pullrequests/stale":{"get":{"summary":"All open Pull Requests in Real Dev Squad","tags":["Pull Requests"],"responses":{"200":{"description":"Pull Requests","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Stale PRs"},"pullRequests":{"type":"array","items":{"$ref":"#/components/schemas/pullRequests"}}}}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/pullrequests/user/:username":{"get":{"summary":"Pull Requests by a user in Real Dev Squad","tags":["Pull Requests"],"responses":{"200":{"description":"Pull Requests","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Pull requests returned successfully!"},"pullRequests":{"type":"array","items":{"$ref":"#/components/schemas/pullRequests"}}}}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/stocks":{"get":{"summary":"Used to get all the stocks","tags":["Stocks"],"responses":{"200":{"description":"returns stocks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/stocks"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}},"post":{"summary":"Used to create new stock","tags":["Stocks"],"requestBody":{"description":"Stock data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/stocks"}}}},"responses":{"200":{"description":"returns newly created stock","content":{"application/json":{"schema":{"$ref":"#/components/schemas/stocks"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/tasks":{"get":{"summary":"Used to get all the tasks","tags":["Tasks"],"responses":{"200":{"description":"returns tasks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}},"post":{"summary":"Used to create new task","tags":["Tasks"],"requestBody":{"description":"Task data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"responses":{"200":{"description":"returns newly created task","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}},"patch":{"summary":"Used to update task details","tags":["Tasks"],"requestBody":{"description":"Task data to be updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"responses":{"204":{"description":"no content"},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/tasks/self":{"get":{"summary":"Use to get all the tasks of the logged in user","tags":["Tasks"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"returns all tasks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/trade/stock/new/self":{"post":{"summary":"Used for new trading request","tags":["Trading"],"security":[{"bearerAuth":[]}],"requestBody":{"description":"Trading details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/trading"}}}},"responses":{"200":{"description":"Successful trading details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tradingSuccess"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/users/self":{"patch":{"summary":"Use to update the user data.","requestBody":{"description":"User data to be updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content"},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}},"get":{"summary":"Use to get self details.","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/users":{"get":{"summary":"Get all the users in system.","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User details","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Users returned successfully!"},"users":{"type":"array","items":{"$ref":"#/components/schemas/users"}}}}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}}},"/users/isUsernameAvailable/:username":{"get":{"summary":"check user exists or not","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User Availability","content":{"application/json":{"schema":{"$ref":"#/components/schemas/userAvailable"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/users/:username":{"get":{"summary":"Get the details of user with provided id.","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/wallet/":{"get":{"summary":"Gets the user wallet details","tags":["wallet"],"responses":{"200":{"description":"Return wallet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/wallet"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/wallet/:username":{"get":{"summary":"Gets the user wallet details for a username, if you are an authorized superuser","tags":["wallet"],"responses":{"200":{"description":"Return wallet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/wallet"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}}}} +{"openapi":"3.0.1","info":{"version":"1.0.0","title":"RDS API documentation","description":"This is documentation for Real Dev Squad's API. Find out more about Real dev squad at [http://realdevsquad.com](http://realdevsquad.com)","contact":{"name":"Real Dev Squad","url":"http://realdevsquad.com"}},"tags":[{"name":"Healthcheck","description":"API for health check in the system"},{"name":"Authentication","description":"Authentication routes"}],"servers":[{"url":"http://localhost:3000","description":"Local server URL"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"healthCheck":{"type":"object","properties":{"uptime":{"type":"number"}}},"tasks":{"type":"object","properties":{"title":{"type":"string"},"purpose":{"type":"string"},"featureUrl":{"type":"string"},"type":{"type":"string"},"links":{"type":"array","items":{"link1":{"type":"string"}}},"endsOn":{"type":"string"},"startedOn":{"type":"string"},"status":{"type":"string"},"ownerId":{"type":"string"},"percentCompleted":{"type":"number"},"dependsOn":{"type":"array","items":{"taskid":{"type":"string"}}},"participants":{"type":"array","items":{"userid":{"type":"string"}}},"completionAward":{"type":"object","properties":{"gold":{"type":"number"},"silver":{"type":"number"},"bronze":{"type":"number"}}},"lossRate":{"type":"object","properties":{"gold":{"type":"number"},"silver":{"type":"number"},"bronze":{"type":"number"}}},"isNoteworthy":{"type":"boolean"}}},"contributions":{"type":"object","properties":{"noteworthy":{"type":"array","items":{"type":"object","properties":{"task":{"type":"object","properties":{"title":{"type":"string"},"purpose":{"type":"string"},"featureUrl":{"type":"string"},"endsOn":{"type":"string"},"startedOn":{"type":"string"},"status":{"type":"string"},"dependsOn":{"type":"array","items":{"type":"string"}},"participants":{"type":"array","items":{"type":"object","properties":{"firstname":{"type":"string"},"lastname":{"type":"string"},"img":{"type":"string"},"username":{"type":"string"}}}},"isNoteworthy":{"type":"boolean"}}},"prList":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"url":{"type":"string"},"state":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"raisedBy":{"type":"string"}}}}}}},"all":{"type":"array","items":{"type":"object","properties":{"task":{"type":"object","properties":{"title":{"type":"string"},"purpose":{"type":"string"},"featureUrl":{"type":"string"},"endsOn":{"type":"string"},"startedOn":{"type":"string"},"status":{"type":"string"},"dependsOn":{"type":"array","items":{"type":"string"}},"participants":{"type":"array","items":{"type":"object","properties":{"firstname":{"type":"string"},"lastname":{"type":"string"},"img":{"type":"string"},"username":{"type":"string"}}}},"isNoteworthy":{"type":"boolean"}}},"prList":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"url":{"type":"string"},"state":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"raisedBy":{"type":"string"}}}}}}}}},"challenges":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"level":{"type":"string"},"start_date":{"type":"string"},"end_date":{"type":"string"},"is_active":{"type":"boolean"},"participants":{"type":"array","items":[]}}},"pullRequests":{"type":"object","properties":{"title":{"type":"string"},"url":{"type":"string"},"state":{"type":"string"},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"readyForReview":{"type":"boolean"},"labels":{"type":"array","items":[]},"assignees":{"type":"array","items":[]}}},"users":{"type":"object","properties":{"username":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"yoe":{"type":"number"},"company":{"type":"string"},"designation":{"type":"string"},"img":{"type":"string"},"github_display_name":{"type":"string"},"github_id":{"type":"string"},"linkedin_id":{"type":"string"},"twitter_id":{"type":"string"},"instagram_id":{"type":"string"},"site":{"type":"string"},"isMember":{"type":"boolean"},"tokens":{"type":"object"}}},"badges":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"imgUrl":{"type":"string"},"users":{"type":"array","items":{"type":"string"}}}},"userAvailable":{"type":"object","properties":{"isUsernameAvailable":{"type":"boolean"}}},"stocks":{"type":"object","properties":{"name":{"type":"string"},"price":{"type":"number"},"quantity":{"type":"number"}}},"trading":{"type":"object","properties":{"stockId":{"type":"string"},"tradeType":{"type":"string"},"stockName":{"type":"string"},"quantity":{"type":"number"},"listedPrice":{"type":"number"},"totalPrice":{"type":"number"}}},"tradingSuccess":{"type":"object","properties":{"userBalance":{"type":"number"}}},"userStocks":{"type":"object","properties":{"userId":{"type":"string"},"stockId":{"type":"string"},"stockName":{"type":"string"},"quantity":{"type":"number"},"orderValue":{"type":"number"},"initialStockValue":{"type":"number"}}},"auctions":{"type":"object","properties":{"id":{"type":"string"},"seller":{"type":"string"},"item_type":{"type":"string"},"quantity":{"type":"number"},"highest_bid":{"type":"number"},"highest_bidder":{"type":"number"},"start_time":{"type":"number"},"end_time":{"type":"number"},"bidders_and_bids":{"type":"array"}}},"errors":{"unAuthorized":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}},"notFound":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}},"forbidden":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}},"badImplementation":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}},"serverUnavailable":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"paths":{"/auctions/:id":{"get":{"summary":"Fetches auction details for given auctionId","tags":["Auctions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Auction details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/auctions"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/auctions":{"get":{"summary":"Get all the active (ongoing) auctions","tags":["Auctions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"All ongoing auctions","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Auctions returned successfully!"},"auctions":{"type":"array","items":{"$ref":"#/components/schemas/auctions"}}}}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}},"post":{"summary":"Creates a new auction","tags":["Auctions"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"New auction","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Auction created successfully!"},"id":{"type":"string"}}}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/auctions/bid/:id":{"post":{"summary":"Makes a new bid given auctionId","tags":["Auctions"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"New bid","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Successfully placed bid!"},"id":{"type":"string"}}}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/auth/github/callback":{"get":{"summary":"Authenticates the user using the GitHub Oauth 2.0. Redirects to the UI on successful login","tags":["Authentication"],"parameters":[{"in":"query","name":"code","required":true,"type":"string","description":"Temporary code returned by GitHub Oauth"}],"responses":{"302":{"description":"Redirects to the UI on successful login","headers":{"Cookie":{"type":"string","description":"Cookie containing authentication token"},"Location":{"type":"string","description":"Redirection URL"}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}}}}},"/badges":{"get":{"summary":"Get all the badges in system.","tags":["Badges"],"responses":{"200":{"description":"Badge details","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Badges returned successfully!"},"badges":{"type":"array","items":{"$ref":"#/components/schemas/badges"}}}}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}}},"/challenges":{"get":{"summary":"Used to get all the challenges","tags":["Challenges"],"responses":{"200":{"description":"Return challenges","content":{"application/json":{"schema":{"$ref":"#/components/schemas/challenges"}}}},"404":{"description":"No challenges found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}},"post":{"summary":"Post new challenge","tags":["Challenges"],"responses":{"200":{"description":"Post challenge","content":{"application/json":{"schema":{"$ref":"#/components/schemas/challenges"}}}},"404":{"description":"Unable to add challenge","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}}},"/challenges/subscribe":{"post":{"summary":"Subscribe user to challenge","tags":["Challenges"],"responses":{"200":{"description":"Subscribed sucessfully","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"User has subscribed to challenge"}}}}}},"404":{"description":"Unable to add challenge","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}}},"/contributions/{username}":{"get":{"summary":"Used to get all the contributions of user","tags":["Contributions"],"responses":{"200":{"description":"Return contributions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/contributions"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/healthcheck":{"get":{"summary":"Use to check health status of the server.","tags":["Healthcheck"],"responses":{"200":{"description":"Server uptime status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/healthCheck"}}}}}}},"/healthcheck/v2":{"get":{"summary":"Sample route to test authentication middleware.","tags":["Healthcheck"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Server uptime status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/healthCheck"}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}}}}},"/members":{"get":{"summary":"Gets details of all the Real Dev Squad members","tags":["Members"],"responses":{"200":{"description":"Details of all the RDS members","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/members/idle":{"get":{"summary":"Gets details of idle members of the Real Dev Squad","tags":["Members"],"responses":{"200":{"description":"Details of inactive/idle members of the RDS members","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/pullrequests/open":{"get":{"summary":"Latest 10 Pull Requests in Real Dev Squad","tags":["Pull Requests"],"responses":{"200":{"description":"Pull Requests","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Open PRs"},"pullRequests":{"type":"array","items":{"$ref":"#/components/schemas/pullRequests"}}}}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/pullrequests/stale":{"get":{"summary":"All open Pull Requests in Real Dev Squad","tags":["Pull Requests"],"responses":{"200":{"description":"Pull Requests","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Stale PRs"},"pullRequests":{"type":"array","items":{"$ref":"#/components/schemas/pullRequests"}}}}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/pullrequests/user/:username":{"get":{"summary":"Pull Requests by a user in Real Dev Squad","tags":["Pull Requests"],"responses":{"200":{"description":"Pull Requests","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Pull requests returned successfully!"},"pullRequests":{"type":"array","items":{"$ref":"#/components/schemas/pullRequests"}}}}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/stocks":{"get":{"summary":"Used to get all the stocks","tags":["Stocks"],"responses":{"200":{"description":"returns stocks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/stocks"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}},"post":{"summary":"Used to create new stock","tags":["Stocks"],"requestBody":{"description":"Stock data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/stocks"}}}},"responses":{"200":{"description":"returns newly created stock","content":{"application/json":{"schema":{"$ref":"#/components/schemas/stocks"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/stocks/user/self":{"get":{"summary":"Used to get all the stocks of the user","tags":["User Stocks"],"responses":{"200":{"description":"returns stocks of the user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/userStocks"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/tasks":{"get":{"summary":"Used to get all the tasks","tags":["Tasks"],"responses":{"200":{"description":"returns tasks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}},"post":{"summary":"Used to create new task","tags":["Tasks"],"requestBody":{"description":"Task data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"responses":{"200":{"description":"returns newly created task","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}},"patch":{"summary":"Used to update task details","tags":["Tasks"],"requestBody":{"description":"Task data to be updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"responses":{"204":{"description":"no content"},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/tasks/self":{"get":{"summary":"Use to get all the tasks of the logged in user","tags":["Tasks"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"returns all tasks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tasks"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/trade/stock/new/self":{"post":{"summary":"Used for new trading request","tags":["Trading"],"security":[{"bearerAuth":[]}],"requestBody":{"description":"Trading details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/trading"}}}},"responses":{"200":{"description":"Successful trading details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/tradingSuccess"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/users/self":{"patch":{"summary":"Use to update the user data.","requestBody":{"description":"User data to be updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content"},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}},"get":{"summary":"Use to get self details.","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/users":{"get":{"summary":"Get all the users in system.","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User details","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Users returned successfully!"},"users":{"type":"array","items":{"$ref":"#/components/schemas/users"}}}}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"503":{"description":"serverUnavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/serverUnavailable"}}}}}}},"/users/isUsernameAvailable/:username":{"get":{"summary":"check user exists or not","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User Availability","content":{"application/json":{"schema":{"$ref":"#/components/schemas/userAvailable"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/users/:username":{"get":{"summary":"Get the details of user with provided id.","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"User details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/users"}}}},"404":{"description":"notFound","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/notFound"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/wallet/":{"get":{"summary":"Gets the user wallet details","tags":["wallet"],"responses":{"200":{"description":"Return wallet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/wallet"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}},"/wallet/:username":{"get":{"summary":"Gets the user wallet details for a username, if you are an authorized superuser","tags":["wallet"],"responses":{"200":{"description":"Return wallet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/wallet"}}}},"401":{"description":"unAuthorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/unAuthorized"}}}},"403":{"description":"forbidden","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/forbidden"}}}},"500":{"description":"badImplementation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/errors/badImplementation"}}}}}}}}} \ No newline at end of file diff --git a/routes/stocks.js b/routes/stocks.js index f2907dbd6..5c057ef5b 100644 --- a/routes/stocks.js +++ b/routes/stocks.js @@ -2,7 +2,7 @@ const express = require('express') const router = express.Router() const authenticate = require('../middlewares/authenticate') const authorization = require('../middlewares/authorization') -const { addNewStock, fetchStocks } = require('../controllers/stocksController') +const { addNewStock, fetchStocks, getUserStocks } = require('../controllers/stocksController') const { createStock } = require('../middlewares/validators/stocks') /** @@ -64,4 +64,28 @@ router.get('/', fetchStocks) */ router.post('/', authenticate, authorization, createStock, addNewStock) +/** + * @swagger + * /stocks/user/self: + * get: + * summary: Used to get all the stocks of the user + * tags: + * - User Stocks + * responses: + * 200: + * description: returns stocks of the user + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/userStocks' + * 500: + * description: badImplementation + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/errors/badImplementation' + */ + +router.get('/user/self', authenticate, getUserStocks) + module.exports = router diff --git a/routes/users.js b/routes/users.js index cd9f523d7..24320e11c 100644 --- a/routes/users.js +++ b/routes/users.js @@ -3,7 +3,6 @@ const router = express.Router() const authenticate = require('../middlewares/authenticate') const usersController = require('../controllers/usersController') const userValidator = require('../middlewares/validators/user') -const { getUserStocks } = require('../controllers/stocksController') /** * @swagger @@ -210,28 +209,4 @@ router.get('/isUsernameAvailable/:username', authenticate, usersController.getUs */ router.get('/:username', usersController.getUser) -/** - * @swagger - * /stocks/self: - * get: - * summary: Used to get all the stocks - * tags: - * - Users Stocks - * responses: - * 200: - * description: returns stocks of the user - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/userStocks' - * 500: - * description: badImplementation - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/errors/badImplementation' - */ - -router.get('/stocks/self', authenticate, getUserStocks) - module.exports = router From b2cd138a77efde53e934a063fd6f021608731fcf Mon Sep 17 00:00:00 2001 From: Sumit Dhanania Date: Sun, 28 Mar 2021 17:49:42 +0530 Subject: [PATCH 04/13] refactor code to fetch user stocks --- controllers/tradingController.js | 2 +- models/stocks.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/controllers/tradingController.js b/controllers/tradingController.js index bf1654dc6..cc9c58fff 100644 --- a/controllers/tradingController.js +++ b/controllers/tradingController.js @@ -21,7 +21,7 @@ const trade = async (req, res) => { return res.json({ userBalance }) } catch (err) { - logger.error(`Error while updating task: ${err}`) + logger.error(`Error during trading: ${err}`) return res.boom.badImplementation('An internal server error occurred') } } diff --git a/models/stocks.js b/models/stocks.js index 7a546ce8f..73001b684 100644 --- a/models/stocks.js +++ b/models/stocks.js @@ -47,8 +47,9 @@ const fetchStocks = async () => { const fetchUserStocks = async (userId, stockId = null) => { try { let userStocksRef = '' + const query = userStocksModel.where('userId', '==', userId) if (stockId) { - userStocksRef = await userStocksModel.where('userId', '==', userId).where('stockId', '==', stockId).get() + userStocksRef = await query.where('stockId', '==', stockId).get() const [userStocks] = userStocksRef.docs if (userStocks) { return { id: userStocks.id, ...userStocks.data() } @@ -56,7 +57,7 @@ const fetchUserStocks = async (userId, stockId = null) => { return {} } - userStocksRef = await userStocksModel.where('userId', '==', userId).get() + userStocksRef = await query.get() const userStocks = [] userStocksRef.forEach((stock) => { userStocks.push({ From 2d78b752673a2791a532e5d7947543cd027242fe Mon Sep 17 00:00:00 2001 From: Sumit Dhanania Date: Sun, 11 Apr 2021 21:14:04 +0530 Subject: [PATCH 05/13] Move trading logic to a service file --- controllers/tradingController.js | 4 ++-- models/trading.js => services/tradingService.js | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename models/trading.js => services/tradingService.js (100%) diff --git a/controllers/tradingController.js b/controllers/tradingController.js index cc9c58fff..c6ce381ca 100644 --- a/controllers/tradingController.js +++ b/controllers/tradingController.js @@ -1,4 +1,4 @@ -const tradeModel = require('../models/trading') +const tradeService = require('../services/tradingService') /** * New Trading Request * @@ -13,7 +13,7 @@ const trade = async (req, res) => { username, userId } - const { canUserTrade, errorMessage, userBalance } = await tradeModel.trade(tradeStockData) + const { canUserTrade, errorMessage, userBalance } = await tradeService.trade(tradeStockData) if (!canUserTrade) { return res.boom.forbidden(errorMessage) diff --git a/models/trading.js b/services/tradingService.js similarity index 100% rename from models/trading.js rename to services/tradingService.js From e33ae7af685c477d9ffbf0c21b64e05baa2f550b Mon Sep 17 00:00:00 2001 From: Sumit Dhanania Date: Mon, 19 Apr 2021 18:19:34 +0530 Subject: [PATCH 06/13] Add 401 unauthorize --- routes/stocks.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/routes/stocks.js b/routes/stocks.js index 188149893..e72937d83 100644 --- a/routes/stocks.js +++ b/routes/stocks.js @@ -78,6 +78,12 @@ router.post('/', authenticate, authorization, createStock, addNewStock) * application/json: * schema: * $ref: '#/components/schemas/userStocks' + * 401: + * description: unAuthorized + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/errors/unAuthorized' * 500: * description: badImplementation * content: From 5c69f89a087ba93589bd4a0019be2f618aa3529b Mon Sep 17 00:00:00 2001 From: Sumit Dhanania Date: Mon, 19 Apr 2021 18:27:44 +0530 Subject: [PATCH 07/13] simplify code --- models/stocks.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/models/stocks.js b/models/stocks.js index 73001b684..2bf73f6e6 100644 --- a/models/stocks.js +++ b/models/stocks.js @@ -83,9 +83,7 @@ const createUserStock = async (userId, stockData) => { ...stockData } const { id } = await userStocksModel.add(userStocks) - return { - id - } + return { id } } catch (err) { logger.error('Error creating user stocks', err) throw err @@ -106,10 +104,7 @@ const updateUserStocks = async (userId, stockData) => { const userStocksRef = userStocksModel.doc(userStocks.id) const res = await userStocksRef.update(stockData) - if (res) { - return true - } - return false + return !!res } catch (err) { logger.error('Error updating users stocks', err) throw err From 620a5dabdbfcf3aa901dbec9921b3c6c1713a0a0 Mon Sep 17 00:00:00 2001 From: Sumit Dhanania Date: Mon, 26 Apr 2021 14:43:16 +0530 Subject: [PATCH 08/13] Use constants for currencies --- controllers/stocks.js | 2 +- services/tradingService.js | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/controllers/stocks.js b/controllers/stocks.js index da567e7fd..3e486ed3d 100644 --- a/controllers/stocks.js +++ b/controllers/stocks.js @@ -43,7 +43,7 @@ const fetchStocks = async (req, res) => { * @param req {Object} - Express request object * @param res {Object} - Express response object */ -const getUserStocks = async (req, res, next) => { +const getUserStocks = async (req, res) => { try { const { id: userId } = req.userData const userStocks = await stocks.fetchUserStocks(userId) diff --git a/services/tradingService.js b/services/tradingService.js index 6564c4def..3068860f6 100644 --- a/services/tradingService.js +++ b/services/tradingService.js @@ -4,6 +4,7 @@ const transactionsModel = firestore.collection('transactions') const tradeLogsModel = firestore.collection('trade-logs') const { fetchWallet, updateWallet } = require('../models/wallets') const { fetchUserStocks, updateUserStocks } = require('../models/stocks') +const { DINERO } = require('../constants/wallets') const INSUFFICIENT_FUNDS = 'Trade was not successful due to insufficient funds' const INSUFFICIENT_QUANTITIES = 'Trade was not successful because you do not have enough quantity' @@ -52,17 +53,17 @@ const trade = async (tradeData) => { } quantityToUpdate = quantity + stockData.quantity - userBalance = (quantity * stockData.price) + currencies.dinero + userBalance = (quantity * stockData.price) + currencies.DINERO userStocksQty = userStocks.quantity - quantity break } case 'BUY': { qtyUserCanPurchase = Math.floor(totalPrice / stockData.price) - if (qtyUserCanPurchase <= 0 || totalPrice > currencies.dinero) { + if (qtyUserCanPurchase <= 0 || totalPrice > currencies.DINERO) { return { canUserTrade: false, errorMessage: INSUFFICIENT_FUNDS } } quantityToUpdate = stockData.quantity - qtyUserCanPurchase - userBalance = currencies.dinero - (qtyUserCanPurchase * stockData.price) + userBalance = currencies.DINERO - (qtyUserCanPurchase * stockData.price) userStocksQty = qtyUserCanPurchase initialStockValue = stockData.price @@ -80,7 +81,7 @@ const trade = async (tradeData) => { const orderValue = qtyUserCanPurchase * stockData.price const stockPriceToBeUpdated = getUpdatedPrice(stockData.price) - updatedCurrencyData.dinero = userBalance + updatedCurrencyData.DINERO = userBalance const updatedStockData = { ...stockData, From a324cbca16fb6c6cb5a1feb6d8043e630d1d93e5 Mon Sep 17 00:00:00 2001 From: Sumit Dhanania Date: Mon, 26 Apr 2021 14:53:43 +0530 Subject: [PATCH 09/13] Use constants for currencies --- services/tradingService.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/services/tradingService.js b/services/tradingService.js index 3068860f6..71208e9f8 100644 --- a/services/tradingService.js +++ b/services/tradingService.js @@ -4,7 +4,7 @@ const transactionsModel = firestore.collection('transactions') const tradeLogsModel = firestore.collection('trade-logs') const { fetchWallet, updateWallet } = require('../models/wallets') const { fetchUserStocks, updateUserStocks } = require('../models/stocks') -const { DINERO } = require('../constants/wallets') +const walletConstants = require('../constants/wallets') const INSUFFICIENT_FUNDS = 'Trade was not successful due to insufficient funds' const INSUFFICIENT_QUANTITIES = 'Trade was not successful because you do not have enough quantity' @@ -53,17 +53,17 @@ const trade = async (tradeData) => { } quantityToUpdate = quantity + stockData.quantity - userBalance = (quantity * stockData.price) + currencies.DINERO + userBalance = (quantity * stockData.price) + currencies[walletConstants.DINERO] userStocksQty = userStocks.quantity - quantity break } case 'BUY': { qtyUserCanPurchase = Math.floor(totalPrice / stockData.price) - if (qtyUserCanPurchase <= 0 || totalPrice > currencies.DINERO) { + if (qtyUserCanPurchase <= 0 || totalPrice > currencies[walletConstants.DINERO]) { return { canUserTrade: false, errorMessage: INSUFFICIENT_FUNDS } } quantityToUpdate = stockData.quantity - qtyUserCanPurchase - userBalance = currencies.DINERO - (qtyUserCanPurchase * stockData.price) + userBalance = currencies[walletConstants.DINERO] - (qtyUserCanPurchase * stockData.price) userStocksQty = qtyUserCanPurchase initialStockValue = stockData.price @@ -81,7 +81,7 @@ const trade = async (tradeData) => { const orderValue = qtyUserCanPurchase * stockData.price const stockPriceToBeUpdated = getUpdatedPrice(stockData.price) - updatedCurrencyData.DINERO = userBalance + updatedCurrencyData.walletConstants.DINERO = userBalance const updatedStockData = { ...stockData, From 4668438ae9d425b952b309a27f8d29e283a03723 Mon Sep 17 00:00:00 2001 From: Sumit Dhanania Date: Tue, 27 Apr 2021 16:44:50 +0530 Subject: [PATCH 10/13] Refactor the stocks model --- controllers/stocks.js | 4 ++-- models/stocks.js | 23 ++++------------------- routes/stocks.js | 4 ++-- 3 files changed, 8 insertions(+), 23 deletions(-) diff --git a/controllers/stocks.js b/controllers/stocks.js index 3e486ed3d..dd1259074 100644 --- a/controllers/stocks.js +++ b/controllers/stocks.js @@ -43,7 +43,7 @@ const fetchStocks = async (req, res) => { * @param req {Object} - Express request object * @param res {Object} - Express response object */ -const getUserStocks = async (req, res) => { +const getSelfStocks = async (req, res) => { try { const { id: userId } = req.userData const userStocks = await stocks.fetchUserStocks(userId) @@ -60,5 +60,5 @@ const getUserStocks = async (req, res) => { module.exports = { addNewStock, fetchStocks, - getUserStocks + getSelfStocks } diff --git a/models/stocks.js b/models/stocks.js index 2bf73f6e6..e95e5f2f1 100644 --- a/models/stocks.js +++ b/models/stocks.js @@ -72,24 +72,6 @@ const fetchUserStocks = async (userId, stockId = null) => { } } -/** - * Create user stocks - * @return {Promise} - */ -const createUserStock = async (userId, stockData) => { - try { - const userStocks = { - userId, - ...stockData - } - const { id } = await userStocksModel.add(userStocks) - return { id } - } catch (err) { - logger.error('Error creating user stocks', err) - throw err - } -} - /** * Update Users Stocks * @return {Promise} @@ -98,7 +80,10 @@ const updateUserStocks = async (userId, stockData) => { try { const userStocks = await fetchUserStocks(userId, stockData.stockId) if (!userStocks.id) { - await createUserStock(userId, stockData) + await userStocksModel.add({ + userId, + ...stockData + }) return true } diff --git a/routes/stocks.js b/routes/stocks.js index e72937d83..19ea48d37 100644 --- a/routes/stocks.js +++ b/routes/stocks.js @@ -2,7 +2,7 @@ const express = require('express') const router = express.Router() const authenticate = require('../middlewares/authenticate') const authorization = require('../middlewares/authorization') -const { addNewStock, fetchStocks, getUserStocks } = require('../controllers/stocks') +const { addNewStock, fetchStocks, getSelfStocks } = require('../controllers/stocks') const { createStock } = require('../middlewares/validators/stocks') /** @@ -92,6 +92,6 @@ router.post('/', authenticate, authorization, createStock, addNewStock) * $ref: '#/components/schemas/errors/badImplementation' */ -router.get('/user/self', authenticate, getUserStocks) +router.get('/user/self', authenticate, getSelfStocks) module.exports = router From 7148417bfe537804a2399056442a6d3cbc8882a2 Mon Sep 17 00:00:00 2001 From: Sumit Dhanania Date: Tue, 11 May 2021 12:11:29 +0530 Subject: [PATCH 11/13] Small fix in the currency update --- services/tradingService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/tradingService.js b/services/tradingService.js index 71208e9f8..b63392c15 100644 --- a/services/tradingService.js +++ b/services/tradingService.js @@ -81,7 +81,7 @@ const trade = async (tradeData) => { const orderValue = qtyUserCanPurchase * stockData.price const stockPriceToBeUpdated = getUpdatedPrice(stockData.price) - updatedCurrencyData.walletConstants.DINERO = userBalance + updatedCurrencyData[walletConstants.DINERO] = userBalance const updatedStockData = { ...stockData, From a383c4b2664bdb75fcfd399606d7aba9f65a3086 Mon Sep 17 00:00:00 2001 From: Sumit Dhanania Date: Thu, 13 May 2021 19:44:18 +0530 Subject: [PATCH 12/13] Destructure wallet constant --- services/tradingService.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/services/tradingService.js b/services/tradingService.js index b63392c15..c6e77f494 100644 --- a/services/tradingService.js +++ b/services/tradingService.js @@ -4,7 +4,7 @@ const transactionsModel = firestore.collection('transactions') const tradeLogsModel = firestore.collection('trade-logs') const { fetchWallet, updateWallet } = require('../models/wallets') const { fetchUserStocks, updateUserStocks } = require('../models/stocks') -const walletConstants = require('../constants/wallets') +const { DINERO } = require('../constants/wallets') const INSUFFICIENT_FUNDS = 'Trade was not successful due to insufficient funds' const INSUFFICIENT_QUANTITIES = 'Trade was not successful because you do not have enough quantity' @@ -53,17 +53,17 @@ const trade = async (tradeData) => { } quantityToUpdate = quantity + stockData.quantity - userBalance = (quantity * stockData.price) + currencies[walletConstants.DINERO] + userBalance = (quantity * stockData.price) + currencies[`${DINERO}`] userStocksQty = userStocks.quantity - quantity break } case 'BUY': { qtyUserCanPurchase = Math.floor(totalPrice / stockData.price) - if (qtyUserCanPurchase <= 0 || totalPrice > currencies[walletConstants.DINERO]) { + if (qtyUserCanPurchase <= 0 || totalPrice > currencies[`${DINERO}`]) { return { canUserTrade: false, errorMessage: INSUFFICIENT_FUNDS } } quantityToUpdate = stockData.quantity - qtyUserCanPurchase - userBalance = currencies[walletConstants.DINERO] - (qtyUserCanPurchase * stockData.price) + userBalance = currencies[`${DINERO}`] - (qtyUserCanPurchase * stockData.price) userStocksQty = qtyUserCanPurchase initialStockValue = stockData.price @@ -81,7 +81,7 @@ const trade = async (tradeData) => { const orderValue = qtyUserCanPurchase * stockData.price const stockPriceToBeUpdated = getUpdatedPrice(stockData.price) - updatedCurrencyData[walletConstants.DINERO] = userBalance + updatedCurrencyData[`${DINERO}`] = userBalance const updatedStockData = { ...stockData, From 6310a350e57d46c13f0bce0557d024e68a52d75f Mon Sep 17 00:00:00 2001 From: Sumit Dhanania Date: Thu, 13 May 2021 21:11:34 +0530 Subject: [PATCH 13/13] Change stocks response message --- controllers/stocks.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controllers/stocks.js b/controllers/stocks.js index dd1259074..1df15c829 100644 --- a/controllers/stocks.js +++ b/controllers/stocks.js @@ -29,7 +29,7 @@ const fetchStocks = async (req, res) => { try { const allStock = await stocks.fetchStocks() return res.json({ - message: 'Stocks returned successfully!', + message: allStock.length > 0 ? 'Stocks returned successfully!' : 'No stocks found', stock: allStock.length > 0 ? allStock : [] }) } catch (err) { @@ -48,7 +48,7 @@ const getSelfStocks = async (req, res) => { const { id: userId } = req.userData const userStocks = await stocks.fetchUserStocks(userId) return res.json({ - message: 'User stocks returned successfully!', + message: userStocks.length > 0 ? 'User stocks returned successfully!' : 'No stocks found', userStocks }) } catch (err) {