Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release #55

Merged
merged 31 commits into from
Oct 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d74e60b
🚧 Docker Deployment (WIP)
nmdra Sep 27, 2024
3488715
Merge branch 'development' into release
nmdra Sep 28, 2024
350067d
🚧 Caddy Container config (WIP)
nmdra Sep 28, 2024
6e4eaab
Merge branch 'development' into release
nmdra Sep 28, 2024
e41145d
👷 Github Action for build images
nmdra Sep 28, 2024
bfdc8cb
⚡️ Reduce Image Size
nmdra Sep 28, 2024
3293fcd
🚑️ Fix: fix registry name
nmdra Sep 28, 2024
939d7e4
🚑️ Fix: fix Url
nmdra Sep 28, 2024
568eb5f
👷 Update Docker Image Build
nmdra Sep 29, 2024
a2e2c65
🎨 Update format
nmdra Sep 29, 2024
101c32a
👷 Update Docker Image Build
nmdra Sep 29, 2024
8d98e17
👷 Update Docker Image Build
nmdra Oct 1, 2024
59f7d42
🐛 Fix Bugs
nmdra Oct 1, 2024
86650ae
🐛 Update Docker Image Build
nmdra Oct 3, 2024
cb6f198
👷 Update Github Action
nmdra Oct 3, 2024
b0de8a6
Update docker-build-publish.yml
nmdra Oct 3, 2024
f473400
Update docker-build-publish.yml
nmdra Oct 3, 2024
244a681
⚡️ Update Dockerfile
nmdra Oct 5, 2024
fae9240
⚡️ Update Dockerfile
nmdra Oct 5, 2024
8727ca5
⚡️ Update Dockerfile
nmdra Oct 5, 2024
d1a5640
🐛 Update
nmdra Oct 6, 2024
e585f31
🩹 Update
nmdra Oct 6, 2024
dc4c1e4
Merge branch 'development' into release
nmdra Oct 6, 2024
9fafd0f
🐛 Update
nmdra Oct 6, 2024
e65c531
Merge branch 'release' of https://github.com/nmdra/ITP-Project into r…
nmdra Oct 6, 2024
12b90c1
🎨 update
nmdra Oct 6, 2024
f76011b
🐛 Update
nmdra Oct 6, 2024
8889ff7
💚 Update Github Action
nmdra Oct 6, 2024
c816578
⚡️ Optimize Image Loading
nmdra Oct 6, 2024
7c18d03
💚 Update
nmdra Oct 6, 2024
c5f0e2d
🎨 format
nmdra Oct 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/workflows/docker-build-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Build and Publish Docker Image

# Trigger the workflow on push or pull request to the main branch
on:
push:
# branches:
# - main
# - release
tags:
- 'v*.*.*'
# pull_request:
# branches:
# - main
# - release
workflow_dispatch:

jobs:
build-and-push:
runs-on: ubuntu-latest

steps:
# Step 1: Checkout the repository code
- name: Checkout repository
uses: actions/checkout@v4

# Step 2: Set up Docker Buildx
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

# Step 3: Log in to Docker Hub (or GHCR if you prefer)
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }} # Docker Hub username (use GitHub actor if using GHCR)
password: ${{ secrets.GITHUB_TOKEN }} # Docker Hub password (use GitHub token if using GHCR)

# Step 4: Build and push the backend Docker image
- name: Build and push backend Docker image
run: |
docker build -t ghcr.io/${{ github.repository_owner }}/farmcart-api:latest -f ./backend/Dockerfile.prod ./backend
docker push ghcr.io/${{ github.repository_owner }}/farmcart-api:latest

# Step 5: Build and push the frontend Docker image
- name: Build and push frontend Docker image
run: |
docker build --build-arg VITE_STRIPE_PUBLIC_KEY=${{ secrets.VITE_STRIPE_PUBLIC_KEY }} -t ghcr.io/${{ github.repository_owner }}/farmcart-app:latest -f ./frontend/Dockerfile.prod ./frontend
docker push ghcr.io/${{ github.repository_owner }}/farmcart-app:latest
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ dist-ssr
.env.prod

certs

docker-compose.caddy.yml
4 changes: 4 additions & 0 deletions backend/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.env
.env.example
.node_modules
.editorconfig
44 changes: 13 additions & 31 deletions backend/.env.example
Original file line number Diff line number Diff line change
@@ -1,38 +1,20 @@

<<<<<<< HEAD

PORT=3000
NODE_ENV=development
MONGODB_URI=mongodb+srv://hansagayashan7:kaG2HyFucHLzVAWD@admin.jtibwek.mongodb.net/adminDB?retryWrites=true&w=majority&appName=Admin
=======
PORT=3000
PORT=5000
NODE_ENV=development
MONGODB_URI=mongodb+srv://imashi:ima1234@test1.n9dxa8d.mongodb.net/ITP?retryWrites=true&w=majority&appName=Test1
>>>>>>> 20440c0c5b14ddeacdd8253c03be7a8f21b4202f
MONGODB_URI_ME=mongodb://root:1234@localhost:27017/FarmCart?authSource=admin
JWT_SECRET=4V@qJn!yGg6QtS
MONGODB_URI=<your_mongodb_uri>
JWT_SECRET=<your_jwt_secret>

CLOUDINARY_CLOUD_NAME=dqhdxkfvk
CLOUDINARY_API_KEY=553548617729688
CLOUDINARY_API_SECRET=5QoMfPIgAucfaDz4YHDhE-BBQe0
<<<<<<< HEAD
CLOUDINARY_CLOUD_NAME=<your_cloudinary_cloud_name>
CLOUDINARY_API_KEY=<your_cloudinary_api_key>
CLOUDINARY_API_SECRET=<your_cloudinary_api_secret>

EMAIL_USER=<>
EMAIL_PASS=<>
EMAIL_USER=<your_email_user>
EMAIL_PASS=<your_email_password>
EMAIL_SERVICE=gmail
SITE_URL=http://localhost:5173
=======
>>>>>>> 20440c0c5b14ddeacdd8253c03be7a8f21b4202f

PAYHERE_MERCHANT_ID=1228062
PAYHERE_MERCHANT_SECRET=Mzc4NDA4Mjg3OTkzNzg0MDE3NTkwNTg3Mjc0NjM2Njc4MjU3OTg=

CRYPTO_SECRET_KEY=5QoMfPIgAucfaDz4Y
SITE_URL=http://0.0.0.0:3000

<<<<<<< HEAD
STRIPE_SECRET_KEY=sk_test_51LMEvTC05RrpHY1zrPQtFPDNvm7ljFOIX6Xx0dRFDWEEjVoUD0mBVgGx0jaScbTtiXDcQvNqkJpXyC4ZcQrR8zbT00e7fsuvyX
PAYHERE_MERCHANT_ID=<your_payhere_merchant_id>
PAYHERE_MERCHANT_SECRET=<your_payhere_merchant_secret>

=======
CRYPTO_SECRET_KEY=<your_crypto_secret_key>

STRIPE_SECRET_KEY=sk_test_51LMEvTC05RrpHY1zrPQtFPDNvm7ljFOIX6Xx0dRFDWEEjVoUD0mBVgGx0jaScbTtiXDcQvNqkJpXyC4ZcQrR8zbT00e7fsuvyX
>>>>>>> 20440c0c5b14ddeacdd8253c03be7a8f21b4202f
STRIPE_SECRET_KEY=<your_stripe_secret_key>
22 changes: 19 additions & 3 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
FROM node:22-alpine3.20
# Stage 1: Build and install only production dependencies
FROM node:22-alpine3.20 AS builder

# Set the working directory
WORKDIR /app

# Copy only package.json and package-lock.json to install dependencies first
COPY package*.json ./

RUN npm install
# Install dependencies only, leveraging cache
RUN npm install --omit=dev && npm prune --production

# Copy the rest of the application code
COPY . .

# Stage 2: Final lightweight image for runtime
FROM node:22-alpine3.20

# Set the working directory
WORKDIR /app

# Copy only the necessary files from the builder stage
COPY --from=builder /app /app

# Expose the application on port 5001
EXPOSE 5001

CMD ["npm", "run", "dev"]
# Run the application in development mode
CMD ["npm", "run", "watch"]
29 changes: 29 additions & 0 deletions backend/Dockerfile.prod
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Stage 1: Build the React app
FROM node:22-alpine3.20 AS builder

# Set the working directory
WORKDIR /app

# Copy package.json and package-lock.json
COPY package*.json ./

# Install dependencies
RUN npm install --omit=dev

# Copy all other files and build the React app
COPY . .

# Stage 2: Serve the app
FROM node:22-alpine3.20

# Set the working directory
WORKDIR /app

# Copy the built files from the builder stage
COPY --from=builder /app /app

# Expose the application port
EXPOSE 5002

# Command to run the application
CMD ["node", "--watch", "--env-file=.env.prod", "server.js"]
22 changes: 13 additions & 9 deletions backend/controllers/orderController.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,30 +117,34 @@ export const DeleteOrder = async (req, res) => {

export const getShopByFarmerId = async (req, res) => {
try {
const { id } = req.params;
const { id } = req.params

console.log("farmerid", id)
console.log('farmerid', id)
// Optional: Validate the ID format (assuming MongoDB ObjectId)
if (!id.match(/^[0-9a-fA-F]{24}$/)) {
return res.status(400).json({ message: 'Invalid farmer ID format' });
return res.status(400).json({ message: 'Invalid farmer ID format' })
}

// Find shops associated with the given farmer ID
const shops = await Shop.find({ farmer: id });
const shops = await Shop.find({ farmer: id })

// Check if any shop is found
if (!shops.length) {
return res.status(404).json({ message: 'No shops found for this farmer' });
return res
.status(404)
.json({ message: 'No shops found for this farmer' })
}

// Return the shop(s) found
res.status(200).json(shops);
res.status(200).json(shops)
} catch (error) {
// Return an error with a 500 status for internal server issues
res.status(500).json({ message: 'Failed to retrieve shops', error: error.message });
res.status(500).json({
message: 'Failed to retrieve shops',
error: error.message,
})
}
};

}

export const getOrderById = async (req, res) => {
const { id: orderId } = req.params // Destructure orderId from request query
Expand Down
8 changes: 8 additions & 0 deletions backend/controllers/userController.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export const updateUser = async (req, res, next) => {
defaultAddress,
contactNumber,
pic,
birthday,
} = req.body

try {
Expand All @@ -78,6 +79,7 @@ export const updateUser = async (req, res, next) => {
user.defaultAddress = defaultAddress || user.defaultAddress
user.contactNumber = contactNumber || user.contactNumber
user.pic = pic || user.pic
user.birthday = birthday || user.birthday

// Save updated user
const updatedUser = await user.save()
Expand All @@ -96,6 +98,8 @@ export const updateUser = async (req, res, next) => {
defaultAddress: updatedUser.defaultAddress,
contactNumber: updatedUser.contactNumber,
pic: updatedUser.pic,
isVerified: updatedUser.isVerified,
birthday: updatedUser.birthday,
},
})
} else {
Expand Down Expand Up @@ -136,6 +140,8 @@ export const authUser = async (req, res, next) => {
defaultAddress: user.defaultAddress,
contactNumber: user.contactNumber,
membershipExpires: user.membershipExpires,
isVerified: user.isVerified,
birthday: user.birthday,
})
} else {
res.status(401).json({ message: 'Invalid Password or Email' })
Expand Down Expand Up @@ -191,6 +197,8 @@ export const upgradeMembership = async (req, res, next) => {
defaultAddress: updatedUser.defaultAddress,
contactNumber: updatedUser.contactNumber,
membershipExpires: updatedUser.membershipExpires,
isVerified: updatedUser.isVerified,
birthday: updatedUser.birthday,
},
})
} catch (error) {
Expand Down
15 changes: 15 additions & 0 deletions backend/controllers/userShopController.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,18 @@ export const getShopProductById = asyncHandler(async (req, res) => {
throw new Error('Shop not found')
}
})

export const getRandomProducts = asyncHandler(async (req, res) => {
try {
// Get random 6 products
const randomProducts = await Shop.aggregate([
{ $unwind: '$products' },
{ $sample: { size: 6 } }, // Fetch 6 random products
])

res.json(randomProducts)
} catch (error) {
console.error('Error fetching products:', error)
res.status(500).json({ message: 'Failed to fetch products' })
}
})
4 changes: 4 additions & 0 deletions backend/models/userModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ const userSchema = new mongoose.Schema(
message: '{VALUE} is not a valid contact number!',
},
},
birthday: {
type: Date,
required: false, // Ensure birth date is provided
},
isVerified: {
type: Boolean,
default: false,
Expand Down
23 changes: 13 additions & 10 deletions backend/routes/userShopRoute.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,34 @@
import express from 'express';
import express from 'express'
import {
getShopById,
getShopProducts,
getShopProductById,
getShops,
} from '../controllers/userShopController.js'; // Import the controller functions
import apicache from 'apicache';
getRandomProducts,
} from '../controllers/userShopController.js' // Import the controller functions
import apicache from 'apicache'

// Configure apicache
let cache = apicache.middleware;
let cache = apicache.middleware

const router = express.Router();
const router = express.Router()

// Route to fetch all shops with caching
// GET /api/shops/
router.get('/', cache('5 minutes'), getShops);
router.get('/', cache('5 minutes'), getShops)

// Route to fetch details of a specific shop by ID with caching
// GET /api/shops/:id
router.get('/:id', cache('5 minutes'), getShopById);
router.get('/random', cache('3 minutes'), getRandomProducts)

router.get('/:id', cache('5 minutes'), getShopById)

// Route to fetch all products for a specific shop with caching
// GET /api/shops/:id/products
router.get('/:id/products', cache('10 minutes'), getShopProducts);
router.get('/:id/products', cache('5 minutes'), getShopProducts)

// Route to fetch a specific product from a shop by product ID with caching
// GET /api/shops/:id/products/:productId
router.get('/:id/products/:productId', cache('10 minutes'), getShopProductById);
router.get('/:id/products/:productId', cache('5 minutes'), getShopProductById)

export default router;
export default router
4 changes: 2 additions & 2 deletions backend/utils/generateToken.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import jwt from 'jsonwebtoken'

export const generateToken = (res, userId) => {
const token = jwt.sign({ userId }, process.env.JWT_SECRET, {
expiresIn: '24h',
expiresIn: '72h',
})

// Set the token as a cookie in the response
res.cookie('jwt', token, {
expires: new Date(Date.now() + 48 * 60 * 60 * 1000), // 2 days
expires: new Date(Date.now() + 144 * 60 * 60 * 1000), // 2 days
httpOnly: true, // Prevents client-side JavaScript from accessing the cookie
secure: process.env.NODE_ENV !== 'development', // Cookie sent only over HTTPS if not in development
sameSite: 'strict', // Prevents CSRF attacks
Expand Down
Loading
Loading