Skip to content

Commit

Permalink
Merge pull request #186 from GoSTEAN/serverSetup
Browse files Browse the repository at this point in the history
feat: Setup a backend routes for Land event
  • Loading branch information
fishonamos authored Dec 2, 2024
2 parents dc34012 + 995bec5 commit 60243b2
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 15 deletions.
26 changes: 12 additions & 14 deletions app/server/routes/landRoutes.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
// const express = require('express');
// const router = express.Router();
// const landController = require('../controllers/landController');
const express = require('express');
const router = express.Router();
const landController = require('../controllers/landController');

// // Remove any authentication middleware for these routes
// router.post('/register', landController.registerLand);
// router.get('/', (req, res, next) => {
// console.log('Received GET request for all lands');
// landController.getAllLands(req, res, next);
// });
// router.get('/:id', landController.getLandById);
// router.get('/:id/verify', landController.verifyLand);
// Base land routes
router.get('/', landController.getAllLands);
router.get('/inspectors', landController.getInspectors);
router.get('/approved', landController.getApprovedLands);
router.get('/transfer-history/:landId', landController.getTransferHistory);

// //Todo: docs, api
// Land verification and details
router.get('/:id', landController.getLandById);
router.get('/:id/verify', landController.verifyLandStatus);


// module.exports = router;
module.exports = router;
70 changes: 70 additions & 0 deletions app/server/src/controllers/landController.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,73 @@ exports.verifyLand = async (req, res, next) => {
next(new CustomError('Error verifying land', 500));
}
};

exports.getInspectors = async (req, res, next) => {
try {
console.log('Fetching inspectors from blockchain');
const inspectors = await blockchainService.getInspectors();
res.status(200).json(inspectors);
} catch (error) {
console.error('Error fetching inspectors:', error);
next(new CustomError('Error fetching inspectors', 500));
}
};

exports.getApprovedLands = async (req, res, next) => {
try {
console.log('Fetching approved lands');
const approvedLands = await blockchainService.getApprovedLands();

// Enrich blockchain data with database information
const enrichedLands = await Promise.all(approvedLands.map(async (land) => {
const dbLand = await Land.findOne({ landId: land.id });
return { ...land, ...dbLand?.toObject() };
}));

res.status(200).json(enrichedLands);
} catch (error) {
console.error('Error fetching approved lands:', error);
next(new CustomError('Error fetching approved lands', 500));
}
};

exports.getTransferHistory = async (req, res, next) => {
try {
const { landId } = req.params;
console.log('Fetching transfer history for land:', landId);

if (!landId) {
throw new CustomError('Land ID is required', 400, 'LAND_ID_REQUIRED');
}

const transferHistory = await blockchainService.getLandTransferHistory(landId);
res.status(200).json(transferHistory);
} catch (error) {
console.error('Error fetching transfer history:', error);
next(new CustomError('Error fetching transfer history', 500));
}
};

exports.verifyLandStatus = async (req, res, next) => {
try {
const { id } = req.params;
console.log('Verifying land status for ID:', id);

if (!id) {
throw new CustomError('Land ID is required', 400, 'LAND_ID_REQUIRED');
}

const verificationResult = await blockchainService.verifyLandStatus(id);

res.status(200).json({
isVerified: verificationResult.isVerified,
message: verificationResult.isVerified
? 'Land is verified in the blockchain registry'
: 'Land is not verified in the blockchain registry',
details: verificationResult.details
});
} catch (error) {
console.error('Error verifying land status:', error);
next(new CustomError('Error verifying land status', 500));
}
};
100 changes: 99 additions & 1 deletion app/server/src/services/blockchainService.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const LandRegistryABI = require('../abis/LandRegistry.json');
const dotenv = require('dotenv');
const crypto = require('crypto');


dotenv.config();

const provider = new ethers.JsonRpcProvider(process.env.ETHEREUM_RPC_URL);
Expand Down Expand Up @@ -106,8 +107,105 @@ async function verifyLand(landId) {
}
}

const getInspectors = async () => {
try {
console.log('Fetching inspectors from blockchain...');
// Call the smart contract method to get inspectors
const inspectors = await contract.getInspectors();

// Transform the raw data into a more useful format
return inspectors.map(inspector => ({
address: inspector.addr,
name: inspector.name,
isActive: inspector.isActive,
registrationDate: new Date(inspector.registrationDate * 1000).toISOString(),
totalLandsInspected: inspector.landsInspected.toString()
}));
} catch (error) {
console.error('Error fetching inspectors:', error);
throw new Error('Failed to fetch inspectors from blockchain');
}
};

const getApprovedLands = async () => {
try {
console.log('Fetching approved lands from blockchain...');
// Get all approved lands from the contract
const approvedLands = await contract.getApprovedLands();

// Transform the raw blockchain data
return approvedLands.map(land => ({
id: land.id.toString(),
owner: land.owner,
location: land.location,
area: ethers.utils.formatUnits(land.area, 'ether'), // If area is stored in wei
landUse: land.landUse,
approvalDate: new Date(land.approvalDate * 1000).toISOString(),
inspectorAddress: land.inspector,
status: land.status
}));
} catch (error) {
console.error('Error fetching approved lands:', error);
throw new Error('Failed to fetch approved lands from blockchain');
}
};

const getLandTransferHistory = async (landId) => {
try {
console.log('Fetching transfer history for landId:', landId);
// Get transfer events for the specific land
const filter = contract.filters.LandTransferred(landId);
const events = await contract.queryFilter(filter, 0, 'latest');

// Transform the events into a readable format
return events.map(event => ({
transactionHash: event.transactionHash,
blockNumber: event.blockNumber,
timestamp: new Date(event.args.timestamp * 1000).toISOString(),
previousOwner: event.args.from,
newOwner: event.args.to,
landId: event.args.landId.toString(),
transferType: event.args.transferType
}));
} catch (error) {
console.error('Error fetching transfer history:', error);
throw new Error('Failed to fetch land transfer history');
}
};

const verifyLandStatus = async (landId) => {
try {
console.log('Verifying land status on blockchain...');
// Get land details from the contract
const landDetails = await contract.getLand(landId);

// Verify the land's status
const isVerified = await contract.isLandVerified(landId);

return {
isVerified,
details: {
owner: landDetails.owner,
status: landDetails.status,
verificationDate: landDetails.verificationDate
? new Date(landDetails.verificationDate * 1000).toISOString()
: null,
inspector: landDetails.inspector,
lastUpdated: new Date(landDetails.lastUpdated * 1000).toISOString()
}
};
} catch (error) {
console.error('Error verifying land status:', error);
throw new Error('Failed to verify land status');
}
};

module.exports = {
registerLand,
getLandDetails,
verifyLand
verifyLand,
getInspectors,
getApprovedLands,
getLandTransferHistory,
verifyLandStatus
};

0 comments on commit 60243b2

Please sign in to comment.