├── assets
├── logos
│ ├── pi_logo.svg
│ └── pi_connect_logo.svg
├── branding
│ ├── brand_guide.pdf
│ └── color_palette.png
├── designs
│ ├── wireframes.png
│ └── mockups
│ │ └── mockups.png
└── icons
│ └── ai_icon.png
├── src
├── frontend
│ ├── assets
│ │ ├── icons
│ │ │ └── icons.png
│ │ └── PiConnet_logo.png
│ ├── css
│ │ ├── FraudAlert.css
│ │ ├── EventCard.css
│ │ ├── AiRecommendations.css
│ │ ├── CommunityFeed.css
│ │ ├── responsive.css
│ │ ├── theme.css
│ │ ├── styles.css
│ │ └── animations.css
│ ├── components
│ │ ├── Footer.js
│ │ ├── EventCard.js
│ │ ├── AiRecommendations.js
│ │ ├── Header.js
│ │ ├── FraudAlert.js
│ │ ├── TransactionList.js
│ │ ├── NotificationBell.js
│ │ └── CommunityFeed.js
│ ├── scripts
│ │ ├── build.js
│ │ └── deploy.js
│ ├── js
│ │ ├── analytics.js
│ │ ├── payment.js
│ │ ├── app.js
│ │ ├── notification.js
│ │ ├── user.js
│ │ └── event.js
│ └── index.html
├── backend
│ ├── routes
│ │ ├── paymentRoutes.js
│ │ ├── userRoutes.js
│ │ ├── analyticsRoutes.js
│ │ ├── charityRoutes.js
│ │ ├── notificationRoutes.js
│ │ ├── fraudRoutes.js
│ │ ├── eventRoutes.js
│ │ ├── communityRoutes.js
│ │ └── aiRoutes.js
│ ├── middleware
│ │ ├── rateLimitMiddleware.js
│ │ ├── errorMiddleware.js
│ │ ├── authMiddleware.js
│ │ └── loggingMiddleware.js
│ ├── models
│ │ ├── notificationModel.js
│ │ ├── charityModel.js
│ │ ├── transactionModel.js
│ │ ├── userModel.js
│ │ ├── analyticsModel.js
│ │ ├── fraudModel.js
│ │ ├── communityModel.js
│ │ └── aiModel.js
│ ├── config.js
│ ├── utils
│ │ ├── smsService.js
│ │ ├── logger.js
│ │ ├── emailService.js
│ │ ├── encryptionService.js
│ │ ├── notificationUtils.js
│ │ └── validationService.js
│ ├── server.js
│ ├── app.js
│ ├── controllers
│ │ ├── paymentController.js
│ │ ├── fraudDetectionController.js
│ │ ├── notificationController.js
│ │ ├── analyticsController.js
│ │ ├── userController.js
│ │ ├── aiController.js
│ │ └── charityController.js
│ └── services
│ │ ├── paymentService.js
│ │ ├── analyticsService.js
│ │ ├── notificationService.js
│ │ ├── charityService.js
│ │ ├── userService.js
│ │ ├── eventService.js
│ │ ├── communityService.js
│ │ ├── fraudService.js
│ │ └── aiService.js
└── scripts
│ ├── build.js
│ ├── test.js
│ └── deploy.js
├── .github
└── ISSUE_TEMPLATE
│ ├── custom.md
│ ├── feature_request.md
│ └── bug_report.md
├── tests
├── setupTests.js
├── integration
│ ├── analyticsRoutes.test.js
│ ├── charityRoutes.test.js
│ ├── notificationRoutes.test.js
│ ├── paymentRoutes.test.js
│ └── userRoutes.test.js
└── unit
│ ├── analyticsController.test.js
│ ├── charityController.test.js
│ ├── paymentController.test.js
│ ├── notificationController.test.js
│ ├── userController.test.js
│ └── aiController.test.js
├── .gitignore
├── ai
├── trainingData
│ ├── userBehaviorData.json
│ ├── transactionData.json
│ ├── feedbackData.json
│ └── communityData.json
├── communityEngagementAnalysis.js
├── sentimentAnalysis.js
├── recommendationEngine.js
├── userBehaviorAnalysis.js
└── fraudDetection.js
├── .circleci
└── config.yml
├── blockchain
├── oracles
│ ├── priceOracle.js
│ └── eventOracle.js
├── smartContracts
│ ├── paymentContract.sol
│ ├── analyticsContract.py
│ ├── aiContract.sol
│ ├── charityContract.sol
│ └── communityContract.sol
└── blockchainService.js
└── docs
└── setup.md
/assets/logos/pi_logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/assets/branding/brand_guide.pdf:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/assets/branding/color_palette.png:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/assets/designs/wireframes.png:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/assets/logos/pi_connect_logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/assets/designs/mockups/mockups.png:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/frontend/assets/icons/icons.png:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/assets/icons/ai_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KOSASIH/PiConnect-Ecosystem/HEAD/assets/icons/ai_icon.png
--------------------------------------------------------------------------------
/src/frontend/assets/PiConnet_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KOSASIH/PiConnect-Ecosystem/HEAD/src/frontend/assets/PiConnet_logo.png
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/custom.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Custom issue template
3 | about: Describe this issue template's purpose here.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/backend/routes/paymentRoutes.js:
--------------------------------------------------------------------------------
1 | // src/backend/routes/paymentRoutes.js
2 | const express = require('express');
3 | const router = express.Router();
4 | const paymentController = require('../controllers/paymentController');
5 |
6 | // Route to process a payment
7 | router.post('/process', paymentController.processPayment);
8 |
9 | // Route to get payment history for a specific user
10 | router.get('/history/:userId', paymentController.getPaymentHistory);
11 |
12 | // Export the payment routes
13 | module.exports = router;
14 |
--------------------------------------------------------------------------------
/src/backend/middleware/rateLimitMiddleware.js:
--------------------------------------------------------------------------------
1 | // src/backend/middleware/rateLimitMiddleware.js
2 | const rateLimit = require('express-rate-limit');
3 |
4 | // Create a rate limiter
5 | const limiter = rateLimit({
6 | windowMs: 15 * 60 * 1000, // 15 minutes
7 | max: 100, // Limit each IP to 100 requests per windowMs
8 | message: {
9 | status: 'error',
10 | message: 'Too many requests, please try again later.',
11 | },
12 | });
13 |
14 | // Export the rate limiting middleware
15 | module.exports = limiter;
16 |
--------------------------------------------------------------------------------
/src/backend/routes/userRoutes.js:
--------------------------------------------------------------------------------
1 | // src/backend/routes/userRoutes.js
2 | const express = require('express');
3 | const router = express.Router();
4 | const userController = require('../controllers/userController');
5 |
6 | // Route to register a new user
7 | router.post('/register', userController.registerUser );
8 |
9 | // Route to log in a user
10 | router.post('/login', userController.loginUser );
11 |
12 | // Route to get user information by user ID
13 | router.get('/:userId', userController.getUser Info);
14 |
15 | // Export the user routes
16 | module.exports = router;
17 |
--------------------------------------------------------------------------------
/tests/setupTests.js:
--------------------------------------------------------------------------------
1 | // tests/setupTests.js
2 |
3 | // Import necessary libraries
4 | import '@testing-library/jest-dom/extend-expect'; // Provides custom matchers for asserting on DOM nodes
5 | import { server } from './mocks/server'; // Import the mock server for API mocking
6 |
7 | // Establish API mocking before all tests.
8 | beforeAll(() => server.listen());
9 |
10 | // Reset any request handlers that are declared as a part of tests (i.e. for testing one-time error scenarios)
11 | afterEach(() => server.resetHandlers());
12 |
13 | // Clean up after the tests are finished.
14 | afterAll(() => server.close());
15 |
--------------------------------------------------------------------------------
/src/backend/routes/analyticsRoutes.js:
--------------------------------------------------------------------------------
1 | // src/backend/routes/analyticsRoutes.js
2 | const express = require('express');
3 | const router = express.Router();
4 | const analyticsController = require('../controllers/analyticsController');
5 |
6 | // Route to get overall analytics data
7 | router.get('/', analyticsController.getAnalyticsData);
8 |
9 | // Route to get payment analytics for a specific user
10 | router.get('/user/:userId', analyticsController.getUser PaymentAnalytics);
11 |
12 | // Route to get charity analytics
13 | router.get('/charity', analyticsController.getCharityAnalytics);
14 |
15 | // Export the analytics routes
16 | module.exports = router;
17 |
--------------------------------------------------------------------------------
/src/backend/middleware/errorMiddleware.js:
--------------------------------------------------------------------------------
1 | // src/backend/middleware/errorMiddleware.js
2 |
3 | // Error handling middleware
4 | const errorMiddleware = (err, req, res, next) => {
5 | // Log the error for debugging
6 | console.error('Error:', err);
7 |
8 | // Set the response status code based on the error type
9 | const statusCode = err.statusCode || 500; // Default to 500 if no status code is set
10 | const message = err.message || 'Internal Server Error';
11 |
12 | // Send the error response
13 | res.status(statusCode).send({
14 | status: 'error',
15 | statusCode,
16 | message,
17 | });
18 | };
19 |
20 | module.exports = errorMiddleware;
21 |
--------------------------------------------------------------------------------
/tests/integration/analyticsRoutes.test.js:
--------------------------------------------------------------------------------
1 | // tests/integration/analyticsRoutes.test.js
2 |
3 | const request = require('supertest');
4 | const app = require('../../backend/app'); // Import your Express app
5 |
6 | describe('Analytics Routes', () => {
7 | it('should return overall analytics data', async () => {
8 | const response = await request(app)
9 | .get('/api/analytics/overview');
10 |
11 | expect(response.status).toBe(200);
12 | expect(response.body).toEqual({
13 | totalUsers: expect.any(Number),
14 | totalDonations: expect.any(Number),
15 | totalCharities: expect.any(Number),
16 | });
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/src/frontend/css/FraudAlert.css:
--------------------------------------------------------------------------------
1 | /* FraudAlert.css */
2 |
3 | .fraud-alert {
4 | padding: 20px;
5 | background-color: #f9f9f9;
6 | border-radius: 8px;
7 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
8 | }
9 |
10 | .loading {
11 | font-size: 16px;
12 | color: #666;
13 | }
14 |
15 | .error {
16 | color: red;
17 | font-weight: bold;
18 | }
19 |
20 | .alert-item {
21 | margin-bottom: 15px;
22 | padding: 10px;
23 | border: 1px solid #ddd;
24 | border-radius: 5px;
25 | background-color: #fff;
26 | }
27 |
28 | .alert-item h3 {
29 | margin: 0;
30 | font-size: 18px;
31 | }
32 |
33 | .alert-item p {
34 | margin: 5px 0;
35 | color: #555;
36 | }
37 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Node.js dependencies
2 | node_modules/
3 | package-lock.json
4 |
5 | # Build output
6 | dist/
7 | build/
8 | *.log
9 |
10 | # Environment variables
11 | .env
12 | .env.local
13 | .env.*.local
14 |
15 | # IDE and editor files
16 | .vscode/
17 | .idea/
18 | *.sublime-project
19 | *.sublime-workspace
20 |
21 | # Operating system files
22 | .DS_Store
23 | Thumbs.db
24 |
25 | # Temporary files
26 | *.tmp
27 | *.temp
28 | *.bak
29 |
30 | # Coverage reports
31 | coverage/
32 | *.lcov
33 |
34 | # Machine learning model files (if applicable)
35 | models/
36 | *.h5
37 | *.pkl
38 |
39 | # Redis data files (if applicable)
40 | *.rdb
41 | *.aof
42 |
43 | # Miscellaneous
44 | *.tgz
45 | *.zip
46 | *.tar.gz
47 |
--------------------------------------------------------------------------------
/tests/unit/analyticsController.test.js:
--------------------------------------------------------------------------------
1 | // tests/unit/analyticsController.test.js
2 |
3 | const analyticsController = require('../../backend/controllers/analyticsController');
4 | const { mockRequest, mockResponse } = require('jest-mock-req-res');
5 |
6 | describe('Analytics Controller', () => {
7 | it('should return overall analytics data', async () => {
8 | const req = mockRequest();
9 | const res = mockResponse();
10 |
11 | await analyticsController.getOverallAnalytics(req, res);
12 |
13 | expect(res.status).toHaveBeenCalledWith(200);
14 | expect(res.json).toHaveBeenCalledWith({
15 | totalUsers: expect.any(Number),
16 | totalDonations: expect.any(Number),
17 | totalCharities: expect.any(Number),
18 | });
19 | });
20 | });
21 |
--------------------------------------------------------------------------------
/src/backend/routes/charityRoutes.js:
--------------------------------------------------------------------------------
1 | // src/backend/routes/charityRoutes.js
2 | const express = require('express');
3 | const router = express.Router();
4 | const charityController = require('../controllers/charityController');
5 |
6 | // Route to create a new charity
7 | router.post('/', charityController.createCharity);
8 |
9 | // Route to get all charities
10 | router.get('/', charityController.getAllCharities);
11 |
12 | // Route to get a specific charity by ID
13 | router.get('/:charityId', charityController.getCharityById);
14 |
15 | // Route to update a charity by ID
16 | router.put('/:charityId', charityController.updateCharity);
17 |
18 | // Route to delete a charity by ID
19 | router.delete('/:charityId', charityController.deleteCharity);
20 |
21 | // Export the charity routes
22 | module.exports = router;
23 |
--------------------------------------------------------------------------------
/src/backend/routes/notificationRoutes.js:
--------------------------------------------------------------------------------
1 | // src/backend/routes/notificationRoutes.js
2 | const express = require('express');
3 | const router = express.Router();
4 | const notificationController = require('../controllers/notificationController');
5 |
6 | // Route to send a notification
7 | router.post('/', notificationController.sendNotification);
8 |
9 | // Route to get notifications for a specific user
10 | router.get('/user/:userId', notificationController.getUser Notifications);
11 |
12 | // Route to mark a notification as read
13 | router.put('/read/:notificationId', notificationController.markNotificationAsRead);
14 |
15 | // Route to delete a notification
16 | router.delete('/:notificationId', notificationController.deleteNotification);
17 |
18 | // Export the notification routes
19 | module.exports = router;
20 |
--------------------------------------------------------------------------------
/src/frontend/css/EventCard.css:
--------------------------------------------------------------------------------
1 | /* EventCard.css */
2 |
3 | .event-card {
4 | padding: 20px;
5 | background-color: #ffffff;
6 | border: 1px solid #ddd;
7 | border-radius: 8px;
8 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
9 | margin-bottom: 20px;
10 | }
11 |
12 | .event-title {
13 | font-size: 20px;
14 | margin: 0 0 10px;
15 | }
16 |
17 | .event-description {
18 | margin: 10px 0;
19 | color: #555;
20 | }
21 |
22 | .event-date,
23 | .event-location,
24 | .event-capacity {
25 | margin: 5px 0;
26 | color: #333;
27 | }
28 |
29 | .register-button {
30 | padding: 10px 15px;
31 | background-color: #007bff;
32 | color: white;
33 | border: none;
34 | border-radius: 5px;
35 | cursor: pointer;
36 | transition: background-color 0.3s ease;
37 | }
38 |
39 | .register-button:hover {
40 | background-color: #0056b3;
41 | }
42 |
--------------------------------------------------------------------------------
/src/backend/models/notificationModel.js:
--------------------------------------------------------------------------------
1 | // src/backend/models/notificationModel.js
2 | const mongoose = require('mongoose');
3 |
4 | // Define the notification schema
5 | const notificationSchema = new mongoose.Schema({
6 | userId: {
7 | type: mongoose.Schema.Types.ObjectId,
8 | ref: 'User ',
9 | required: true
10 | },
11 | message: {
12 | type: String,
13 | required: true
14 | },
15 | createdAt: {
16 | type: Date,
17 | default: Date.now
18 | },
19 | isRead: {
20 | type: Boolean,
21 | default: false
22 | }
23 | });
24 |
25 | // Method to mark notification as read
26 | notificationSchema.methods.markAsRead = function() {
27 | this.isRead = true;
28 | return this.save();
29 | };
30 |
31 | // Export the Notification model
32 | module.exports = mongoose.model('Notification', notificationSchema);
33 |
--------------------------------------------------------------------------------
/src/backend/models/charityModel.js:
--------------------------------------------------------------------------------
1 | // src/backend/models/charityModel.js
2 | const mongoose = require('mongoose');
3 |
4 | // Define the charity schema
5 | const charitySchema = new mongoose.Schema({
6 | name: {
7 | type: String,
8 | required: true,
9 | trim: true
10 | },
11 | description: {
12 | type: String,
13 | required: true
14 | },
15 | createdAt: {
16 | type: Date,
17 | default: Date.now
18 | },
19 | totalDonations: {
20 | type: Number,
21 | default: 0
22 | },
23 | isActive: {
24 | type: Boolean,
25 | default: true
26 | }
27 | });
28 |
29 | // Method to update total donations
30 | charitySchema.methods.updateTotalDonations = function(amount) {
31 | this.totalDonations += amount;
32 | return this.save();
33 | };
34 |
35 | // Export the Charity model
36 | module.exports = mongoose.model('Charity', charitySchema);
37 |
--------------------------------------------------------------------------------
/src/backend/config.js:
--------------------------------------------------------------------------------
1 | // src/backend/config.js
2 | const mongoose = require('mongoose');
3 | const dotenv = require('dotenv');
4 |
5 | // Load environment variables from .env file
6 | dotenv.config();
7 |
8 | // MongoDB connection function
9 | const connectDB = async () => {
10 | try {
11 | const mongoURI = process.env.MONGODB_URI; // MongoDB URI from environment variables
12 | await mongoose.connect(mongoURI, {
13 | useNewUrlParser: true,
14 | useUnifiedTopology: true,
15 | useCreateIndex: true, // Ensure indexes are created
16 | useFindAndModify: false // Avoid deprecation warnings
17 | });
18 | console.log('MongoDB connected successfully');
19 | } catch (error) {
20 | console.error('MongoDB connection failed:', error);
21 | process.exit(1); // Exit the process with failure
22 | }
23 | };
24 |
25 | // Export the connectDB function
26 | module.exports = { connectDB };
27 |
--------------------------------------------------------------------------------
/src/frontend/css/AiRecommendations.css:
--------------------------------------------------------------------------------
1 | /* AiRecommendations.css */
2 |
3 | .ai-recommendations {
4 | padding: 20px;
5 | background-color: #f9f9f9;
6 | border-radius: 8px;
7 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
8 | }
9 |
10 | .loading {
11 | font-size: 16px;
12 | color: #666;
13 | }
14 |
15 | .error {
16 | color: red;
17 | font-weight: bold;
18 | }
19 |
20 | .recommendation-item {
21 | margin-bottom: 15px;
22 | padding: 10px;
23 | border: 1px solid #ddd;
24 | border-radius: 5px;
25 | background-color: #fff;
26 | }
27 |
28 | .recommendation-item h3 {
29 | margin: 0;
30 | font-size: 18px;
31 | }
32 |
33 | .recommendation-item p {
34 | margin: 5px 0;
35 | color: #555;
36 | }
37 |
38 | .recommendation-link {
39 | display: inline-block;
40 | margin-top: 5px;
41 | color: #007bff;
42 | text-decoration: none;
43 | }
44 |
45 | .recommendation-link:hover {
46 | text-decoration: underline;
47 | }
48 |
--------------------------------------------------------------------------------
/src/frontend/components/Footer.js:
--------------------------------------------------------------------------------
1 | // src/frontend/components/Footer.js
2 |
3 | import React from 'react';
4 |
5 | const Footer = () => {
6 | return (
7 |
21 | );
22 | };
23 |
24 | export default Footer;
25 |
--------------------------------------------------------------------------------
/src/backend/middleware/authMiddleware.js:
--------------------------------------------------------------------------------
1 | // src/backend/middleware/authMiddleware.js
2 | const jwt = require('jsonwebtoken');
3 |
4 | // Middleware to authenticate user using JWT
5 | const authMiddleware = (req, res, next) => {
6 | // Get the token from the Authorization header
7 | const token = req.header('Authorization')?.replace('Bearer ', '');
8 |
9 | // Check if token is provided
10 | if (!token) {
11 | return res.status(401).send({ message: 'Access denied. No token provided.' });
12 | }
13 |
14 | try {
15 | // Verify the token
16 | const decoded = jwt.verify(token, process.env.JWT_SECRET);
17 | req.user = decoded; // Attach the decoded user information to the request object
18 | next(); // Proceed to the next middleware or route handler
19 | } catch (error) {
20 | console.error('Token verification error:', error);
21 | res.status(400).send({ message: 'Invalid token.' });
22 | }
23 | };
24 |
25 | module.exports = authMiddleware;
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/src/backend/models/transactionModel.js:
--------------------------------------------------------------------------------
1 | // src/backend/models/transactionModel.js
2 | const mongoose = require('mongoose');
3 |
4 | // Define the transaction schema
5 | const transactionSchema = new mongoose.Schema({
6 | userId: {
7 | type: mongoose.Schema.Types.ObjectId,
8 | ref: 'User ',
9 | required: true
10 | },
11 | amount: {
12 | type: Number,
13 | required: true
14 | },
15 | createdAt: {
16 | type: Date,
17 | default: Date.now
18 | },
19 | status: {
20 | type: String,
21 | enum: ['pending', 'completed', 'failed'],
22 | default: 'pending'
23 | },
24 | description: {
25 | type: String
26 | }
27 | });
28 |
29 | // Method to update the transaction status
30 | transactionSchema.methods.updateStatus = function(newStatus) {
31 | this.status = newStatus;
32 | return this.save();
33 | };
34 |
35 | // Export the Transaction model
36 | module.exports = mongoose.model('Transaction', transactionSchema);
37 |
--------------------------------------------------------------------------------
/src/backend/utils/smsService.js:
--------------------------------------------------------------------------------
1 | // src/backend/utils/smsService.js
2 | const twilio = require('twilio');
3 |
4 | // Initialize Twilio client
5 | const client = new twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);
6 |
7 | // Function to send an SMS
8 | const sendSMS = async (to, message) => {
9 | // Validate input
10 | if (!to || !message) {
11 | throw new Error('Recipient phone number and message are required to send an SMS.');
12 | }
13 |
14 | try {
15 | const sms = await client.messages.create({
16 | body: message,
17 | from: process.env.TWILIO_PHONE_NUMBER, // Your Twilio phone number
18 | to, // Recipient's phone number
19 | });
20 |
21 | console.log('SMS sent:', sms.sid);
22 | return sms;
23 | } catch (error) {
24 | console.error('Error sending SMS:', error);
25 | throw new Error('Failed to send SMS.');
26 | }
27 | };
28 |
29 | // Export the SMS sending function
30 | module.exports = {
31 | sendSMS,
32 | };
33 |
--------------------------------------------------------------------------------
/src/frontend/components/EventCard.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './EventCard.css'; // Import CSS for styling
3 |
4 | const EventCard = ({ event, onRegister }) => {
5 | const handleRegister = () => {
6 | if (onRegister) {
7 | onRegister(event.id); // Call the onRegister function passed as a prop
8 | }
9 | };
10 |
11 | return (
12 |
13 |
{event.title}
14 |
{event.description}
15 |
Date: {new Date(event.date).toLocaleString()}
16 |
Location: {event.location}
17 |
Capacity: {event.capacity} spots available
18 |
21 |
22 | );
23 | };
24 |
25 | export default EventCard;
26 |
--------------------------------------------------------------------------------
/src/backend/models/userModel.js:
--------------------------------------------------------------------------------
1 | // src/backend/models/userModel.js
2 | const mongoose = require('mongoose');
3 |
4 | // Define the user schema
5 | const userSchema = new mongoose.Schema({
6 | username: {
7 | type: String,
8 | required: true,
9 | unique: true,
10 | trim: true
11 | },
12 | password: {
13 | type: String,
14 | required: true
15 | },
16 | email: {
17 | type: String,
18 | required: true,
19 | unique: true,
20 | trim: true
21 | },
22 | createdAt: {
23 | type: Date,
24 | default: Date.now
25 | },
26 | lastLogin: {
27 | type: Date
28 | },
29 | isActive: {
30 | type: Boolean,
31 | default: true
32 | }
33 | });
34 |
35 | // Method to update the last login time
36 | userSchema.methods.updateLastLogin = function() {
37 | this.lastLogin = Date.now();
38 | return this.save();
39 | };
40 |
41 | // Export the User model
42 | module.exports = mongoose.model('User ', userSchema);
43 |
--------------------------------------------------------------------------------
/ai/trainingData/userBehaviorData.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "userId": "user123",
4 | "timestamp": "2023-10-01T12:00:00Z",
5 | "action": "donate",
6 | "amount": 50.0,
7 | "charityId": "charity456",
8 | "location": "New York, USA",
9 | "device": "mobile"
10 | },
11 | {
12 | "userId": "user124",
13 | "timestamp": "2023-10-01T12:05:00Z",
14 | "action": "view",
15 | "charityId": "charity789",
16 | "location": "Los Angeles, USA",
17 | "device": "desktop"
18 | },
19 | {
20 | "userId": "user125",
21 | "timestamp": "2023-10-01T12:10:00Z",
22 | "action": "share",
23 | "charityId": "charity456",
24 | "location": "Chicago, USA",
25 | "device": "tablet"
26 | },
27 | {
28 | "userId": "user123",
29 | "timestamp": "2023-10-01T12:15:00Z",
30 | "action": "comment",
31 | "charityId": "charity456",
32 | "comment": "Great cause!",
33 | "location": "New York, USA",
34 | "device": "mobile"
35 | }
36 | ]
37 |
--------------------------------------------------------------------------------
/src/scripts/build.js:
--------------------------------------------------------------------------------
1 | // build.js
2 |
3 | const path = require('path');
4 | const fs = require('fs');
5 | const webpack = require('webpack');
6 | const webpackConfig = require('./webpack.config.js'); // Import your Webpack configuration
7 |
8 | const build = () => {
9 | console.log('Starting the build process...');
10 |
11 | // Clean the output directory
12 | const outputDir = path.resolve(__dirname, '../dist');
13 | if (fs.existsSync(outputDir)) {
14 | fs.rmdirSync(outputDir, { recursive: true });
15 | }
16 | fs.mkdirSync(outputDir);
17 |
18 | // Run Webpack
19 | webpack(webpackConfig, (err, stats) => {
20 | if (err) {
21 | console.error('Webpack encountered an error:', err);
22 | process.exit(1);
23 | }
24 |
25 | // Log the build stats
26 | console.log(stats.toString({
27 | chunks: false, // Makes the build much quieter
28 | colors: true, // Shows colors in the console
29 | }));
30 |
31 | console.log('Build completed successfully!');
32 | });
33 | };
34 |
35 | // Execute the build function
36 | build();
37 |
--------------------------------------------------------------------------------
/src/scripts/test.js:
--------------------------------------------------------------------------------
1 | // test.js
2 |
3 | const { exec } = require('child_process');
4 |
5 | // Function to execute shell commands
6 | const executeCommand = (command) => {
7 | return new Promise((resolve, reject) => {
8 | exec(command, (error, stdout, stderr) => {
9 | if (error) {
10 | console.error(`Error executing command: ${command}`);
11 | console.error(stderr);
12 | reject(error);
13 | } else {
14 | console.log(stdout);
15 | resolve(stdout);
16 | }
17 | });
18 | });
19 | };
20 |
21 | // Function to run tests
22 | const runTests = async () => {
23 | try {
24 | console.log('Starting test execution...');
25 |
26 | // Step 1: Run Jest tests
27 | console.log('Running tests with Jest...');
28 | await executeCommand('npx jest'); // Adjust the command if necessary
29 |
30 | console.log('All tests completed successfully!');
31 | } catch (error) {
32 | console.error('Test execution failed:', error);
33 | }
34 | };
35 |
36 | // Execute the runTests function
37 | runTests();
38 |
--------------------------------------------------------------------------------
/src/backend/utils/logger.js:
--------------------------------------------------------------------------------
1 | // src/backend/utils/logger.js
2 | const fs = require('fs');
3 | const path = require('path');
4 |
5 | // Define the log file path
6 | const logFilePath = path.join(__dirname, 'application.log');
7 |
8 | // Function to log messages
9 | const logMessage = (message) => {
10 | const timestamp = new Date().toISOString();
11 | const logEntry = `${timestamp} - ${message}\n`;
12 |
13 | // Append the log entry to the log file
14 | fs.appendFile(logFilePath, logEntry, (err) => {
15 | if (err) {
16 | console.error('Failed to write to log file:', err);
17 | }
18 | });
19 | };
20 |
21 | // Function to log errors
22 | const logError = (error) => {
23 | const timestamp = new Date().toISOString();
24 | const logEntry = `${timestamp} - ERROR: ${error}\n`;
25 |
26 | // Append the error entry to the log file
27 | fs.appendFile(logFilePath, logEntry, (err) => {
28 | if (err) {
29 | console.error('Failed to write to log file:', err);
30 | }
31 | });
32 | };
33 |
34 | // Export the logging functions
35 | module.exports = {
36 | logMessage,
37 | logError,
38 | };
39 |
--------------------------------------------------------------------------------
/src/backend/models/analyticsModel.js:
--------------------------------------------------------------------------------
1 | // src/backend/models/analyticsModel.js
2 | const mongoose = require('mongoose');
3 |
4 | // Define the analytics schema
5 | const analyticsSchema = new mongoose.Schema({
6 | totalUsers: {
7 | type: Number,
8 | required: true
9 | },
10 | totalPayments: {
11 | type: Number,
12 | required: true
13 | },
14 | totalPaymentAmount: {
15 | type: Number,
16 | required: true
17 | },
18 | totalCharities: {
19 | type: Number,
20 | required: true
21 | },
22 | createdAt: {
23 | type: Date,
24 | default: Date.now
25 | }
26 | });
27 |
28 | // Method to update analytics data
29 | analyticsSchema.methods.updateAnalytics = function(data) {
30 | this.totalUsers = data.totalUsers || this.totalUsers;
31 | this.totalPayments = data.totalPayments || this.totalPayments;
32 | this.totalPaymentAmount = data.totalPaymentAmount || this.totalPaymentAmount;
33 | this.totalCharities = data.totalCharities || this.totalCharities;
34 | return this.save();
35 | };
36 |
37 | // Export the Analytics model
38 | module.exports = mongoose.model('Analytics', analyticsSchema);
39 |
--------------------------------------------------------------------------------
/tests/integration/charityRoutes.test.js:
--------------------------------------------------------------------------------
1 | // tests/integration/charityRoutes.test.js
2 |
3 | const request = require('supertest');
4 | const app = require('../../backend/app'); // Import your Express app
5 |
6 | describe('Charity Routes', () => {
7 | it('should create a new charity successfully', async () => {
8 | const response = await request(app)
9 | .post('/api/charities')
10 | .send({
11 | name: 'Charity Name',
12 | description: 'Charity Description',
13 | });
14 |
15 | expect(response.status).toBe(201);
16 | expect(response.body.charity).toEqual({
17 | id: expect.any(String),
18 | name: 'Charity Name',
19 | description: 'Charity Description',
20 | });
21 | });
22 |
23 | it('should return an error for missing charity name', async () => {
24 | const response = await request(app)
25 | .post('/api/charities')
26 | .send({
27 | description: 'Charity Description',
28 | });
29 |
30 | expect(response.status).toBe(400);
31 | expect(response.body).toEqual({
32 | message: 'Charity name is required',
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/src/backend/middleware/loggingMiddleware.js:
--------------------------------------------------------------------------------
1 | // loggingMiddleware.js
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const morgan = require('morgan');
6 |
7 | // Create a write stream (in append mode) for logging to a file
8 | const logStream = fs.createWriteStream(path.join(__dirname, '../logs/requests.log'), { flags: 'a' });
9 |
10 | // Setup morgan to log requests to the console and to a file
11 | const requestLogger = morgan('combined', { stream: logStream });
12 |
13 | // Middleware function to log requests
14 | const logRequests = (req, res, next) => {
15 | const { method, url, headers } = req;
16 | const startTime = Date.now();
17 |
18 | // Log the request details
19 | console.log(`[${new Date().toISOString()}] ${method} ${url} - Headers: ${JSON.stringify(headers)}`);
20 |
21 | // Listen for the response to log when it's finished
22 | res.on('finish', () => {
23 | const duration = Date.now() - startTime;
24 | console.log(`[${new Date().toISOString()}] ${method} ${url} - Status: ${res.statusCode} - Duration: ${duration}ms`);
25 | });
26 |
27 | next(); // Call the next middleware or route handler
28 | };
29 |
30 | // Export the middleware
31 | module.exports = {
32 | requestLogger,
33 | logRequests,
34 | };
35 |
--------------------------------------------------------------------------------
/tests/integration/notificationRoutes.test.js:
--------------------------------------------------------------------------------
1 | // tests/integration/notificationRoutes.test.js
2 |
3 | const request = require('supertest');
4 | const app = require('../../backend/app'); // Import your Express app
5 |
6 | describe('Notification Routes', () => {
7 | it('should send a notification successfully', async () => {
8 | const response = await request(app)
9 | .post('/api/notifications')
10 | .send({
11 | userId: 'user123',
12 | message: 'New donation received!',
13 | });
14 |
15 | expect(response.status).toBe(201);
16 | expect(response.body.notification).toEqual({
17 | id: expect.any(String),
18 | message: 'New donation received!',
19 | read: false,
20 | date: expect.any(String),
21 | });
22 | });
23 |
24 | it('should return an error for missing message', async () => {
25 | const response = await request(app)
26 | .post('/api/notifications')
27 | .send({
28 | userId: 'user123',
29 | });
30 |
31 | expect(response.status).toBe(400);
32 | expect(response.body).toEqual({
33 | message: 'Notification message is required',
34 | });
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/tests/integration/paymentRoutes.test.js:
--------------------------------------------------------------------------------
1 | // tests/integration/paymentRoutes.test.js
2 |
3 | const request = require('supertest');
4 | const app = require('../../backend/app'); // Import your Express app
5 |
6 | describe('Payment Routes', () => {
7 | it('should process a payment successfully', async () => {
8 | const response = await request(app)
9 | .post('/api/payments')
10 | .send({
11 | amount: 100,
12 | charityId: 'charity123',
13 | userId: 'user123',
14 | });
15 |
16 | expect(response.status).toBe(200);
17 | expect(response.body).toEqual({
18 | message: 'Payment processed successfully',
19 | transactionId: expect.any(String),
20 | });
21 | });
22 |
23 | it('should return an error for invalid payment amount', async () => {
24 | const response = await request(app)
25 | .post('/api/payments')
26 | .send({
27 | amount: -50,
28 | charityId: 'charity123',
29 | userId: 'user123',
30 | });
31 |
32 | expect(response.status).toBe(400);
33 | expect(response.body).toEqual({
34 | message: 'Invalid payment amount',
35 | });
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/src/frontend/css/CommunityFeed.css:
--------------------------------------------------------------------------------
1 | /* CommunityFeed.css */
2 |
3 | .community-feed {
4 | padding: 20px;
5 | background-color: #f9f9f9;
6 | border-radius: 8px;
7 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
8 | }
9 |
10 | .loading {
11 | font-size: 16px;
12 | color: #666;
13 | }
14 |
15 | .error {
16 | color: red;
17 | font-weight: bold;
18 | }
19 |
20 | .post-item {
21 | margin-bottom: 15px;
22 | padding: 10px;
23 | border: 1px solid #ddd;
24 | border-radius: 5px;
25 | background-color: #fff;
26 | }
27 |
28 | .post-item h3 {
29 | margin: 0;
30 | font-size: 18px;
31 | }
32 |
33 | .post-item p {
34 | margin: 5px 0;
35 | color: #555;
36 | }
37 |
38 | .comments-section {
39 | margin-top: 10px;
40 | }
41 |
42 | .comment-item {
43 | margin: 5px 0;
44 | padding: 5px;
45 | border: 1px solid #ddd;
46 | border-radius: 3px;
47 | background-color: #f1f1f1;
48 | }
49 |
50 | input[type="text"] {
51 | width: calc(100% - 100px);
52 | padding: 5px;
53 | margin-right: 5px;
54 | }
55 |
56 | button {
57 | padding: 5px 10px;
58 | background-color: #007bff;
59 | color: white;
60 | border: none;
61 | border-radius: 3px;
62 | cursor: pointer;
63 | }
64 |
65 | button:hover {
66 | background-color: #0056b3;
67 | }
68 |
--------------------------------------------------------------------------------
/ai/trainingData/transactionData.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "transactionId": "tx001",
4 | "userId": "user123",
5 | "charityId": "charity456",
6 | "amount": 50.0,
7 | "timestamp": "2023-10-01T12:00:00Z",
8 | "paymentMethod": "credit_card",
9 | "status": "completed",
10 | "location": "New York, USA"
11 | },
12 | {
13 | "transactionId": "tx002",
14 | "userId": "user124",
15 | "charityId": "charity789",
16 | "amount": 25.0,
17 | "timestamp": "2023-10-01T12:05:00Z",
18 | "paymentMethod": "paypal",
19 | "status": "completed",
20 | "location": "Los Angeles, USA"
21 | },
22 | {
23 | "transactionId": "tx003",
24 | "userId": "user125",
25 | "charityId": "charity456",
26 | "amount": 100.0,
27 | "timestamp": "2023-10-01T12:10:00Z",
28 | "paymentMethod": "bank_transfer",
29 | "status": "pending",
30 | "location": "Chicago, USA"
31 | },
32 | {
33 | "transactionId": "tx004",
34 | "userId": "user123",
35 | "charityId": "charity456",
36 | "amount": 75.0,
37 | "timestamp": "2023-10-01T12:15:00Z",
38 | "paymentMethod": "credit_card",
39 | "status": "completed",
40 | "location": "New York, USA"
41 | }
42 | ]
43 |
--------------------------------------------------------------------------------
/tests/integration/userRoutes.test.js:
--------------------------------------------------------------------------------
1 | // tests/integration/userRoutes.test.js
2 |
3 | const request = require('supertest');
4 | const app = require('../../backend/app'); // Import your Express app
5 |
6 | describe('User Routes', () => {
7 | it('should register a new user successfully', async () => {
8 | const response = await request(app)
9 | .post('/api/users/register')
10 | .send({
11 | username: 'testuser',
12 | password: 'password123',
13 | email: 'test@example.com',
14 | });
15 |
16 | expect(response.status).toBe(201);
17 | expect(response.body.user).toEqual({
18 | id: expect.any(String),
19 | username: 'testuser',
20 | email: 'test@example.com',
21 | });
22 | });
23 |
24 | it('should return an error for duplicate username', async () => {
25 | const response = await request(app)
26 | .post('/api/users/register')
27 | .send({
28 | username: 'existinguser',
29 | password: 'password123',
30 | email: 'test@example.com',
31 | });
32 |
33 | expect(response.status).toBe(400);
34 | expect(response.body).toEqual({
35 | message: 'User already exists',
36 | });
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # Use the latest 2.1 version of CircleCI pipeline process engine.
2 | # See: https://circleci.com/docs/configuration-reference
3 | version: 2.1
4 |
5 | # Define a job to be invoked later in a workflow.
6 | # See: https://circleci.com/docs/jobs-steps/#jobs-overview & https://circleci.com/docs/configuration-reference/#jobs
7 | jobs:
8 | say-hello:
9 | # Specify the execution environment. You can specify an image from Docker Hub or use one of our convenience images from CircleCI's Developer Hub.
10 | # See: https://circleci.com/docs/executor-intro/ & https://circleci.com/docs/configuration-reference/#executor-job
11 | docker:
12 | # Specify the version you desire here
13 | # See: https://circleci.com/developer/images/image/cimg/base
14 | - image: cimg/base:current
15 |
16 | # Add steps to the job
17 | # See: https://circleci.com/docs/jobs-steps/#steps-overview & https://circleci.com/docs/configuration-reference/#steps
18 | steps:
19 | # Checkout the code as the first step.
20 | - checkout
21 | - run:
22 | name: "Say hello"
23 | command: "echo Hello, World!"
24 |
25 | # Orchestrate jobs using workflows
26 | # See: https://circleci.com/docs/workflows/ & https://circleci.com/docs/configuration-reference/#workflows
27 | workflows:
28 | say-hello-workflow: # This is the name of the workflow, feel free to change it to better match your workflow.
29 | # Inside the workflow, you define the jobs you want to run.
30 | jobs:
31 | - say-hello
--------------------------------------------------------------------------------
/tests/unit/charityController.test.js:
--------------------------------------------------------------------------------
1 | // tests/unit/charityController.test.js
2 |
3 | const charityController = require('../../backend/controllers/charityController');
4 | const { mockRequest, mockResponse } = require('jest-mock-req-res');
5 |
6 | describe('Charity Controller', () => {
7 | it('should create a new charity successfully', async () => {
8 | const req = mockRequest({
9 | body: {
10 | name: 'Charity Name',
11 | description: 'Charity Description',
12 | },
13 | });
14 | const res = mockResponse();
15 |
16 | await charityController.createCharity(req, res);
17 |
18 | expect(res.status).toHaveBeenCalledWith(201);
19 | expect(res.json).toHaveBeenCalledWith({
20 | charity: {
21 | id: expect.any(String),
22 | name: 'Charity Name',
23 | description: 'Charity Description',
24 | },
25 | });
26 | });
27 |
28 | it('should return an error for missing charity name', async () => {
29 | const req = mockRequest({
30 | body: {
31 | description: 'Charity Description',
32 | },
33 | });
34 | const res = mockResponse();
35 |
36 | await charityController.createCharity(req, res);
37 |
38 | expect(res.status).toHaveBeenCalledWith(400);
39 | expect(res.json).toHaveBeenCalledWith({
40 | message: 'Charity name is required',
41 | });
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/tests/unit/paymentController.test.js:
--------------------------------------------------------------------------------
1 | // tests/unit/paymentController.test.js
2 |
3 | const paymentController = require('../../backend/controllers/paymentController');
4 | const { mockRequest, mockResponse } = require('jest-mock-req-res');
5 |
6 | describe('Payment Controller', () => {
7 | it('should process a payment successfully', async () => {
8 | const req = mockRequest({
9 | body: {
10 | amount: 100,
11 | charityId: 'charity123',
12 | userId: 'user123',
13 | },
14 | });
15 | const res = mockResponse();
16 |
17 | await paymentController.processPayment(req, res);
18 |
19 | expect(res.status).toHaveBeenCalledWith(200);
20 | expect(res.json).toHaveBeenCalledWith({
21 | message: 'Payment processed successfully',
22 | transactionId: expect.any(String),
23 | });
24 | });
25 |
26 | it('should return an error for invalid payment amount', async () => {
27 | const req = mockRequest({
28 | body: {
29 | amount: -50,
30 | charityId: 'charity123',
31 | userId: 'user123',
32 | },
33 | });
34 | const res = mockResponse();
35 |
36 | await paymentController.processPayment(req, res);
37 |
38 | expect(res.status).toHaveBeenCalledWith(400);
39 | expect(res.json).toHaveBeenCalledWith({
40 | message: 'Invalid payment amount',
41 | });
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/src/backend/utils/emailService.js:
--------------------------------------------------------------------------------
1 | // src/backend/utils/emailService.js
2 | const nodemailer = require('nodemailer');
3 |
4 | // Create a transporter for sending emails
5 | const transporter = nodemailer.createTransport({
6 | host: process.env.EMAIL_HOST, // e.g., 'smtp.example.com'
7 | port: process.env.EMAIL_PORT, // e.g., 587
8 | secure: process.env.EMAIL_SECURE === 'true', // true for 465, false for other ports
9 | auth: {
10 | user: process.env.EMAIL_USER, // Your email address
11 | pass: process.env.EMAIL_PASS, // Your email password or app-specific password
12 | },
13 | });
14 |
15 | // Function to send an email
16 | const sendEmail = async (to, subject, text, html) => {
17 | // Validate input
18 | if (!to || !subject || !text) {
19 | throw new Error('Recipient, subject, and text are required to send an email.');
20 | }
21 |
22 | const mailOptions = {
23 | from: process.env.EMAIL_FROM, // Sender address
24 | to, // List of recipients
25 | subject, // Subject line
26 | text, // Plain text body
27 | html, // HTML body (optional)
28 | };
29 |
30 | try {
31 | const info = await transporter.sendMail(mailOptions);
32 | console.log('Email sent:', info.response);
33 | return info;
34 | } catch (error) {
35 | console.error('Error sending email:', error);
36 | throw new Error('Failed to send email.');
37 | }
38 | };
39 |
40 | // Export the email sending function
41 | module.exports = {
42 | sendEmail,
43 | };
44 |
--------------------------------------------------------------------------------
/tests/unit/notificationController.test.js:
--------------------------------------------------------------------------------
1 | // tests/unit/notificationController.test.js
2 |
3 | const notificationController = require('../../backend/controllers/notificationController');
4 | const { mockRequest, mockResponse } = require('jest-mock-req-res');
5 |
6 | describe('Notification Controller', () => {
7 | it('should send a notification successfully', async () => {
8 | const req = mockRequest({
9 | body: {
10 | userId: 'user123',
11 | message: 'New donation received!',
12 | },
13 | });
14 | const res = mockResponse();
15 |
16 | await notificationController.sendNotification(req, res);
17 |
18 | expect(res.status).toHaveBeenCalledWith(201);
19 | expect(res.json).toHaveBeenCalledWith({
20 | notification: {
21 | id: expect.any(String),
22 | message: 'New donation received!',
23 | read: false,
24 | date: expect.any(String),
25 | },
26 | });
27 | });
28 |
29 | it('should return an error for missing message', async () => {
30 | const req = mockRequest({
31 | body: {
32 | userId: 'user123',
33 | },
34 | });
35 | const res = mockResponse();
36 |
37 | await notificationController.sendNotification(req, res);
38 |
39 | expect(res.status).toHaveBeenCalledWith(400);
40 | expect(res.json).toHaveBeenCalledWith({
41 | message: 'Notification message is required',
42 | });
43 | });
44 | });
45 |
--------------------------------------------------------------------------------
/tests/unit/userController.test.js:
--------------------------------------------------------------------------------
1 | // tests/unit/userController.test.js
2 |
3 | const userController = require('../../backend/controllers/userController');
4 | const { mockRequest, mockResponse } = require('jest-mock-req-res');
5 |
6 | describe('User Controller', () => {
7 | it('should register a new user successfully', async () => {
8 | const req = mockRequest({
9 | body: {
10 | username: 'testuser',
11 | password: 'password123',
12 | email: 'test@example.com',
13 | },
14 | });
15 | const res = mockResponse();
16 |
17 | await userController.register(req, res);
18 |
19 | expect(res.status).toHaveBeenCalledWith(201);
20 | expect(res.json).toHaveBeenCalledWith({
21 | user: {
22 | id: expect.any(String),
23 | username: 'testuser',
24 | email: 'test@example.com',
25 | },
26 | });
27 | });
28 |
29 | it('should return an error for duplicate username', async () => {
30 | const req = mockRequest({
31 | body: {
32 | username: 'existinguser',
33 | password: 'password123',
34 | email: 'test@example.com',
35 | },
36 | });
37 | const res = mockResponse();
38 |
39 | await userController.register(req, res);
40 |
41 | expect(res.status).toHaveBeenCalledWith(400);
42 | expect(res.json).toHaveBeenCalledWith({
43 | message: 'User already exists',
44 | });
45 | });
46 | });
47 |
--------------------------------------------------------------------------------
/src/backend/server.js:
--------------------------------------------------------------------------------
1 | // src/backend/server.js
2 | const express = require('express');
3 | const mongoose = require('mongoose');
4 | const dotenv = require('dotenv');
5 | const cors = require('cors');
6 | const bodyParser = require('body-parser');
7 | const userRoutes = require('./routes/userRoutes');
8 | const charityRoutes = require('./routes/charityRoutes');
9 | const analyticsRoutes = require('./routes/analyticsRoutes');
10 | const notificationRoutes = require('./routes/notificationRoutes');
11 | const errorMiddleware = require('./middleware/errorMiddleware');
12 | const rateLimitMiddleware = require('./middleware/rateLimitMiddleware');
13 |
14 | // Load environment variables from .env file
15 | dotenv.config();
16 |
17 | // Create an Express application
18 | const app = express();
19 |
20 | // Middleware
21 | app.use(cors()); // Enable CORS
22 | app.use(bodyParser.json()); // Parse JSON request bodies
23 | app.use(rateLimitMiddleware); // Apply rate limiting middleware
24 |
25 | // Connect to MongoDB
26 | mongoose.connect(process.env.MONGODB_URI, {
27 | useNewUrlParser: true,
28 | useUnifiedTopology: true,
29 | })
30 | .then(() => {
31 | console.log('Connected to MongoDB');
32 | })
33 | .catch((error) => {
34 | console.error('MongoDB connection error:', error);
35 | });
36 |
37 | // Define API routes
38 | app.use('/api/users', userRoutes);
39 | app.use('/api/charities', charityRoutes);
40 | app.use('/api/analytics', analyticsRoutes);
41 | app.use('/api/notifications', notificationRoutes);
42 |
43 | // Error handling middleware
44 | app.use(errorMiddleware);
45 |
46 | // Start the server
47 | const PORT = process.env.PORT || 5000;
48 | app.listen(PORT, () => {
49 | console.log(`Server is running on port ${PORT}`);
50 | });
51 |
--------------------------------------------------------------------------------
/src/backend/app.js:
--------------------------------------------------------------------------------
1 | // backend/app.js
2 | const express = require('express');
3 | const mongoose = require('mongoose');
4 | const bodyParser = require('body-parser');
5 | const cors = require('cors');
6 | const morgan = require('morgan');
7 | const helmet = require('helmet');
8 | const rateLimit = require('express-rate-limit');
9 | const { connectDB } = require('./config');
10 |
11 | // Import routes
12 | const paymentRoutes = require('./routes/paymentRoutes');
13 | const userRoutes = require('./routes/userRoutes');
14 | const charityRoutes = require('./routes/charityRoutes');
15 | const analyticsRoutes = require('./routes/analyticsRoutes');
16 | const notificationRoutes = require('./routes/notificationRoutes');
17 |
18 | const app = express();
19 |
20 | // Middleware
21 | app.use(cors());
22 | app.use(helmet());
23 | app.use(morgan('combined'));
24 | app.use(bodyParser.json());
25 | app.use(bodyParser.urlencoded({ extended: true }));
26 |
27 | // Rate limiting
28 | const limiter = rateLimit({
29 | windowMs: 15 * 60 * 1000, // 15 minutes
30 | max: 100 // Limit each IP to 100 requests per windowMs
31 | });
32 | app.use(limiter);
33 |
34 | // Database connection
35 | connectDB();
36 |
37 | // Routes
38 | app.use('/api/payments', paymentRoutes);
39 | app.use('/api/users', userRoutes);
40 | app.use('/api/charities', charityRoutes);
41 | app.use('/api/analytics', analyticsRoutes);
42 | app.use('/api/notifications', notificationRoutes);
43 |
44 | // Error handling middleware
45 | app.use((err, req, res, next) => {
46 | console.error(err.stack);
47 | res.status(500).send({ message: 'Something went wrong!' });
48 | });
49 |
50 | // Start the server
51 | const PORT = process.env.PORT || 5000;
52 | app.listen(PORT, () => {
53 | console.log(`Server is running on port ${PORT}`);
54 | });
55 |
--------------------------------------------------------------------------------
/src/backend/models/fraudModel.js:
--------------------------------------------------------------------------------
1 | // fraudModel.js
2 |
3 | const mongoose = require('mongoose');
4 |
5 | // Define the schema for fraud detection data
6 | const fraudSchema = new mongoose.Schema({
7 | transactionId: {
8 | type: mongoose.Schema.Types.ObjectId,
9 | ref: 'Transaction', // Reference to the Transaction model
10 | required: true,
11 | },
12 | userId: {
13 | type: mongoose.Schema.Types.ObjectId,
14 | ref: 'User ', // Reference to the User model
15 | required: true,
16 | },
17 | reportedBy: {
18 | type: mongoose.Schema.Types.ObjectId,
19 | ref: 'User ', // Reference to the User model who reported the fraud
20 | required: true,
21 | },
22 | reason: {
23 | type: String,
24 | required: true, // Reason for reporting the fraud
25 | },
26 | status: {
27 | type: String,
28 | enum: ['pending', 'investigating', 'resolved', 'dismissed'], // Status of the fraud report
29 | default: 'pending',
30 | },
31 | createdAt: {
32 | type: Date,
33 | default: Date.now, // Timestamp of when the fraud report was created
34 | },
35 | updatedAt: {
36 | type: Date,
37 | default: Date.now, // Timestamp of the last update to the fraud report
38 | },
39 | fraudScore: {
40 | type: Number,
41 | default: 0, // Score indicating the likelihood of fraud (can be calculated based on various factors)
42 | },
43 | additionalInfo: {
44 | type: Map,
45 | of: String, // Additional information related to the fraud case (e.g., IP address, device info)
46 | },
47 | });
48 |
49 | // Create the Fraud model
50 | const FraudModel = mongoose.model('Fraud', fraudSchema);
51 |
52 | module.exports = FraudModel;
53 |
--------------------------------------------------------------------------------
/src/backend/controllers/paymentController.js:
--------------------------------------------------------------------------------
1 | // src/backend/controllers/paymentController.js
2 | const Payment = require('../models/transactionModel');
3 | const User = require('../models/userModel'); // Assuming you have a User model for user validation
4 |
5 | // Process a payment
6 | exports.processPayment = async (req, res) => {
7 | const { userId, amount } = req.body;
8 |
9 | // Validate input
10 | if (!userId || !amount) {
11 | return res.status(400).send({ message: 'User ID and amount are required.' });
12 | }
13 |
14 | try {
15 | // Check if user exists
16 | const user = await User.findById(userId);
17 | if (!user) {
18 | return res.status(404).send({ message: 'User not found.' });
19 | }
20 |
21 | // Create a new payment transaction
22 | const newPayment = new Payment({ userId, amount });
23 | await newPayment.save();
24 |
25 | // Respond with success
26 | res.status(201).send({ message: 'Payment processed successfully', payment: newPayment });
27 | } catch (error) {
28 | console.error('Payment processing error:', error);
29 | res.status(500).send({ message: 'Payment processing failed', error });
30 | }
31 | };
32 |
33 | // Get payment history for a user
34 | exports.getPaymentHistory = async (req, res) => {
35 | const { userId } = req.params;
36 |
37 | try {
38 | // Retrieve payment history for the user
39 | const payments = await Payment.find({ userId }).sort({ createdAt: -1 }); // Sort by most recent
40 | res.status(200).send(payments);
41 | } catch (error) {
42 | console.error('Error retrieving payment history:', error);
43 | res.status(500).send({ message: 'Failed to retrieve payment history', error });
44 | }
45 | };
46 |
--------------------------------------------------------------------------------
/src/backend/models/communityModel.js:
--------------------------------------------------------------------------------
1 | // communityModel.js
2 |
3 | const mongoose = require('mongoose');
4 |
5 | // Define the schema for community engagement data
6 | const communitySchema = new mongoose.Schema({
7 | userId: {
8 | type: mongoose.Schema.Types.ObjectId,
9 | ref: 'User ', // Reference to the User model
10 | required: true,
11 | },
12 | title: {
13 | type: String,
14 | required: true, // Title of the post
15 | trim: true,
16 | },
17 | content: {
18 | type: String,
19 | required: true, // Content of the post
20 | trim: true,
21 | },
22 | createdAt: {
23 | type: Date,
24 | default: Date.now, // Timestamp of when the post was created
25 | },
26 | updatedAt: {
27 | type: Date,
28 | default: Date.now, // Timestamp of the last update to the post
29 | },
30 | likes: [
31 | {
32 | type: mongoose.Schema.Types.ObjectId,
33 | ref: 'User ', // Users who liked the post
34 | },
35 | ],
36 | comments: [
37 | {
38 | userId: {
39 | type: mongoose.Schema.Types.ObjectId,
40 | ref: 'User ', // Reference to the User model who commented
41 | required: true,
42 | },
43 | content: {
44 | type: String,
45 | required: true, // Content of the comment
46 | trim: true,
47 | },
48 | createdAt: {
49 | type: Date,
50 | default: Date.now, // Timestamp of when the comment was created
51 | },
52 | },
53 | ],
54 | });
55 |
56 | // Create the Community model
57 | const CommunityModel = mongoose.model('Community', communitySchema);
58 |
59 | module.exports = CommunityModel;
60 |
--------------------------------------------------------------------------------
/src/backend/services/paymentService.js:
--------------------------------------------------------------------------------
1 | // src/backend/services/paymentService.js
2 | const Transaction = require('../models/transactionModel');
3 | const User = require('../models/userModel');
4 | const Charity = require('../models/charityModel');
5 |
6 | // Process a payment
7 | const processPayment = async (userId, amount, charityId) => {
8 | // Validate input
9 | if (!userId || !amount || !charityId) {
10 | throw new Error('User ID, amount, and charity ID are required.');
11 | }
12 |
13 | // Check if user exists
14 | const user = await User.findById(userId);
15 | if (!user) {
16 | throw new Error('User not found.');
17 | }
18 |
19 | // Check if charity exists
20 | const charity = await Charity.findById(charityId);
21 | if (!charity) {
22 | throw new Error('Charity not found.');
23 | }
24 |
25 | // Create a new transaction
26 | const transaction = new Transaction({
27 | userId,
28 | amount,
29 | status: 'completed', // Assuming the payment is successful
30 | description: `Donation to ${charity.name}`
31 | });
32 |
33 | // Save the transaction
34 | await transaction.save();
35 |
36 | // Update the charity's total donations
37 | await charity.updateTotalDonations(amount);
38 |
39 | return transaction;
40 | };
41 |
42 | // Get payment history for a user
43 | const getPaymentHistory = async (userId) => {
44 | // Validate input
45 | if (!userId) {
46 | throw new Error('User ID is required.');
47 | }
48 |
49 | // Retrieve payment history for the user
50 | const payments = await Transaction.find({ userId }).sort({ createdAt: -1 });
51 | return payments;
52 | };
53 |
54 | // Export the payment service functions
55 | module.exports = {
56 | processPayment,
57 | getPaymentHistory
58 | };
59 |
--------------------------------------------------------------------------------
/src/frontend/components/AiRecommendations.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import axios from 'axios';
3 | import './AiRecommendations.css'; // Import CSS for styling
4 |
5 | const AiRecommendations = () => {
6 | const [recommendations, setRecommendations] = useState([]);
7 | const [loading, setLoading] = useState(true);
8 | const [error, setError] = useState(null);
9 |
10 | // Fetch AI recommendations from the backend
11 | const fetchRecommendations = async () => {
12 | try {
13 | const response = await axios.get('/api/recommendations'); // Adjust the API endpoint as needed
14 | setRecommendations(response.data);
15 | } catch (err) {
16 | setError('Failed to fetch recommendations. Please try again later.');
17 | } finally {
18 | setLoading(false);
19 | }
20 | };
21 |
22 | useEffect(() => {
23 | fetchRecommendations();
24 | }, []);
25 |
26 | if (loading) {
27 | return Loading recommendations...
;
28 | }
29 |
30 | if (error) {
31 | return {error}
;
32 | }
33 |
34 | return (
35 |
36 |
AI Recommendations
37 |
46 |
47 | );
48 | };
49 |
50 | export default AiRecommendations;
51 |
--------------------------------------------------------------------------------
/src/frontend/components/Header.js:
--------------------------------------------------------------------------------
1 | // src/frontend/components/Header.js
2 |
3 | import React from 'react';
4 | import { Link } from 'react-router-dom';
5 |
6 | const Header = ({ user, onLogout }) => {
7 | return (
8 |
39 | );
40 | };
41 |
42 | export default Header;
43 |
--------------------------------------------------------------------------------
/blockchain/oracles/priceOracle.js:
--------------------------------------------------------------------------------
1 | const axios = require('axios');
2 | const { EventEmitter } = require('events');
3 |
4 | class PriceOracle extends EventEmitter {
5 | constructor(apiUrl, assetSymbol) {
6 | super();
7 | this.apiUrl = apiUrl;
8 | this.assetSymbol = assetSymbol;
9 | this.currentPrice = 0;
10 | this.updateInterval = 60000; // Update every minute
11 | this.startPriceFeed();
12 | }
13 |
14 | // Function to fetch the latest price from the API
15 | async fetchPrice() {
16 | try {
17 | const response = await axios.get(this.apiUrl);
18 | const price = this.extractPrice(response.data);
19 | this.currentPrice = price;
20 | this.emit('priceUpdated', price); // Emit event when price is updated
21 | } catch (error) {
22 | console.error('Error fetching price:', error.message);
23 | }
24 | }
25 |
26 | // Function to extract the price from the API response
27 | extractPrice(data) {
28 | // Assuming the API returns a JSON object with a 'price' field
29 | // Modify this according to the actual API response structure
30 | return data.price;
31 | }
32 |
33 | // Function to start the price feed
34 | startPriceFeed() {
35 | this.fetchPrice(); // Initial fetch
36 | setInterval(() => {
37 | this.fetchPrice();
38 | }, this.updateInterval);
39 | }
40 |
41 | // Function to get the current price
42 | getCurrentPrice() {
43 | return this.currentPrice;
44 | }
45 | }
46 |
47 | // Example usage
48 | const priceOracle = new PriceOracle('https://api.example.com/price', 'ETH');
49 |
50 | priceOracle.on('priceUpdated', (newPrice) => {
51 | console.log(`New price for ${priceOracle.assetSymbol}: $${newPrice}`);
52 | });
53 |
54 | // Export the PriceOracle class
55 | module.exports = PriceOracle;
56 |
--------------------------------------------------------------------------------
/src/backend/utils/encryptionService.js:
--------------------------------------------------------------------------------
1 | // encryptionService.js
2 |
3 | const crypto = require('crypto');
4 |
5 | // Define constants for encryption
6 | const ALGORITHM = 'aes-256-cbc'; // Encryption algorithm
7 | const SECRET_KEY = process.env.SECRET_KEY || 'your-secret-key'; // Secret key for encryption (should be stored securely)
8 | const IV_LENGTH = 16; // Initialization vector length
9 |
10 | // Function to encrypt data
11 | const encrypt = (text) => {
12 | // Generate a random initialization vector
13 | const iv = crypto.randomBytes(IV_LENGTH);
14 | const cipher = crypto.createCipheriv(ALGORITHM, Buffer.from(SECRET_KEY, 'hex'), iv);
15 | let encrypted = cipher.update(text, 'utf8', 'hex');
16 | encrypted += cipher.final('hex');
17 |
18 | // Return the IV and encrypted data as a single string
19 | return iv.toString('hex') + ':' + encrypted;
20 | };
21 |
22 | // Function to decrypt data
23 | const decrypt = (encryptedText) => {
24 | // Split the IV and encrypted data
25 | const parts = encryptedText.split(':');
26 | const iv = Buffer.from(parts.shift(), 'hex');
27 | const encryptedData = Buffer.from(parts.join(':'), 'hex');
28 | const decipher = crypto.createDecipheriv(ALGORITHM, Buffer.from(SECRET_KEY, 'hex'), iv);
29 | let decrypted = decipher.update(encryptedData, 'hex', 'utf8');
30 | decrypted += decipher.final('utf8');
31 | return decrypted;
32 | };
33 |
34 | // Function to hash passwords
35 | const hashPassword = (password) => {
36 | return crypto.createHash('sha256').update(password).digest('hex');
37 | };
38 |
39 | // Function to compare hashed passwords
40 | const comparePasswords = (password, hashedPassword) => {
41 | const hashedInputPassword = hashPassword(password);
42 | return hashedInputPassword === hashedPassword;
43 | };
44 |
45 | module.exports = {
46 | encrypt,
47 | decrypt,
48 | hashPassword,
49 | comparePasswords,
50 | };
51 |
--------------------------------------------------------------------------------
/src/backend/models/aiModel.js:
--------------------------------------------------------------------------------
1 | // aiModel.js
2 |
3 | const mongoose = require('mongoose');
4 |
5 | // Define the schema for AI recommendations
6 | const aiSchema = new mongoose.Schema({
7 | userId: {
8 | type: mongoose.Schema.Types.ObjectId,
9 | ref: 'User ', // Reference to the User model
10 | required: true,
11 | },
12 | preferences: {
13 | type: Map,
14 | of: String, // Key-value pairs for user preferences (e.g., category: 'sports', genre: 'action')
15 | },
16 | interactionHistory: [
17 | {
18 | itemId: {
19 | type: mongoose.Schema.Types.ObjectId,
20 | ref: 'Item', // Reference to the Item model (could be products, articles, etc.)
21 | required: true,
22 | },
23 | interactionType: {
24 | type: String,
25 | enum: ['viewed', 'liked', 'shared', 'commented'], // Types of interactions
26 | required: true,
27 | },
28 | timestamp: {
29 | type: Date,
30 | default: Date.now, // Timestamp of the interaction
31 | },
32 | },
33 | ],
34 | recommendations: [
35 | {
36 | itemId: {
37 | type: mongoose.Schema.Types.ObjectId,
38 | ref: 'Item', // Reference to the Item model
39 | required: true,
40 | },
41 | score: {
42 | type: Number,
43 | required: true, // Score indicating the strength of the recommendation
44 | },
45 | createdAt: {
46 | type: Date,
47 | default: Date.now, // Timestamp of when the recommendation was generated
48 | },
49 | },
50 | ],
51 | });
52 |
53 | // Create the AI model
54 | const AIModel = mongoose.model('AI', aiSchema);
55 |
56 | module.exports = AIModel;
57 |
--------------------------------------------------------------------------------
/blockchain/smartContracts/paymentContract.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.0;
3 |
4 | import "@openzeppelin/contracts/access/Ownable.sol";
5 | import "@openzeppelin/contracts/utils/math/SafeMath.sol";
6 |
7 | contract PaymentContract is Ownable {
8 | using SafeMath for uint256;
9 |
10 | // Event to log payments
11 | event PaymentReceived(address indexed donor, uint256 amount, string charityId);
12 | event Withdrawal(address indexed to, uint256 amount);
13 |
14 | // Mapping to track total donations per charity
15 | mapping(string => uint256) public charityDonations;
16 |
17 | // Function to receive payments
18 | receive() external payable {
19 | require(msg.value > 0, "Payment must be greater than zero");
20 | emit PaymentReceived(msg.sender, msg.value, "default"); // Default charity ID
21 | }
22 |
23 | // Function to donate to a specific charity
24 | function donate(string memory charityId) public payable {
25 | require(msg.value > 0, "Donation must be greater than zero");
26 | charityDonations[charityId] = charityDonations[charityId].add(msg.value);
27 | emit PaymentReceived(msg.sender, msg.value, charityId);
28 | }
29 |
30 | // Function to withdraw funds to a specified address
31 | function withdraw(address payable to, uint256 amount) public onlyOwner {
32 | require(amount <= address(this).balance, "Insufficient balance");
33 | to.transfer(amount);
34 | emit Withdrawal(to, amount);
35 | }
36 |
37 | // Function to get the total donations for a specific charity
38 | function getTotalDonations(string memory charityId) public view returns (uint256) {
39 | return charityDonations[charityId];
40 | }
41 |
42 | // Function to get the contract's balance
43 | function getContractBalance() public view returns (uint256) {
44 | return address(this).balance;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/frontend/components/FraudAlert.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import axios from 'axios';
3 | import './FraudAlert.css'; // Import CSS for styling
4 |
5 | const FraudAlert = () => {
6 | const [alerts, setAlerts] = useState([]);
7 | const [loading, setLoading] = useState(true);
8 | const [error, setError] = useState(null);
9 |
10 | // Fetch fraud alerts from the backend
11 | const fetchFraudAlerts = async () => {
12 | try {
13 | const response = await axios.get('/api/fraud-alerts'); // Adjust the API endpoint as needed
14 | setAlerts(response.data);
15 | } catch (err) {
16 | setError('Failed to fetch fraud alerts. Please try again later.');
17 | } finally {
18 | setLoading(false);
19 | }
20 | };
21 |
22 | useEffect(() => {
23 | fetchFraudAlerts();
24 | }, []);
25 |
26 | if (loading) {
27 | return Loading fraud alerts...
;
28 | }
29 |
30 | if (error) {
31 | return {error}
;
32 | }
33 |
34 | return (
35 |
36 |
Fraud Alerts
37 | {alerts.length === 0 ? (
38 |
No fraud alerts at this time.
39 | ) : (
40 |
50 | )}
51 |
52 | );
53 | };
54 |
55 | export default FraudAlert;
56 |
--------------------------------------------------------------------------------
/src/frontend/css/responsive.css:
--------------------------------------------------------------------------------
1 | /* Responsive Design Styles */
2 |
3 | /* General Styles for Mobile Devices */
4 | body {
5 | padding: 0 10px; /* Add padding for mobile */
6 | }
7 |
8 | /* Header Styles */
9 | header {
10 | padding: 40px 10px; /* Adjust padding for smaller screens */
11 | }
12 |
13 | header h1 {
14 | font-size: 2.5rem; /* Smaller font size for mobile */
15 | }
16 |
17 | header p {
18 | font-size: 1.2rem; /* Smaller font size for mobile */
19 | }
20 |
21 | /* Main Content Styles */
22 | .container {
23 | padding: 10px; /* Reduce padding for mobile */
24 | }
25 |
26 | /* Charity Card Styles */
27 | .charity-card {
28 | margin: 10px 0; /* Stack cards vertically on mobile */
29 | }
30 |
31 | /* Footer Styles */
32 | footer {
33 | padding: 15px 0; /* Adjust footer padding for mobile */
34 | }
35 |
36 | /* Tablet Styles */
37 | @media (min-width: 768px) and (max-width: 1024px) {
38 | header {
39 | padding: 50px 20px; /* Adjust padding for tablets */
40 | }
41 |
42 | header h1 {
43 | font-size: 2.8rem; /* Slightly larger font size for tablets */
44 | }
45 |
46 | header p {
47 | font-size: 1.4rem; /* Slightly larger font size for tablets */
48 | }
49 |
50 | .charity-card {
51 | margin: 15px; /* Add margin for cards on tablets */
52 | }
53 |
54 | footer {
55 | padding: 20px 0; /* Adjust footer padding for tablets */
56 | }
57 | }
58 |
59 | /* Desktop Styles */
60 | @media (min-width: 1025px) {
61 | header {
62 | padding: 60px 20px; /* Original padding for desktops */
63 | }
64 |
65 | header h1 {
66 | font-size: 3rem; /* Original font size for desktops */
67 | }
68 |
69 | header p {
70 | font-size: 1.5rem; /* Original font size for desktops */
71 | }
72 |
73 | .charity-card {
74 | margin: 20px; /* Original margin for cards on desktops */
75 | }
76 |
77 | footer {
78 | padding: 25px 0; /* Original footer padding for desktops */
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/scripts/deploy.js:
--------------------------------------------------------------------------------
1 | // deploy.js
2 |
3 | const { exec } = require('child_process');
4 | const path = require('path');
5 | const fs = require('fs');
6 |
7 | // Configuration
8 | const remoteServer = 'user@your-server.com'; // Replace with your server's SSH user and address
9 | const remotePath = '/var/www/your-app'; // Replace with the path on your server
10 | const localBuildPath = path.resolve(__dirname, '../dist'); // Path to the built application
11 |
12 | // Function to execute shell commands
13 | const executeCommand = (command) => {
14 | return new Promise((resolve, reject) => {
15 | exec(command, (error, stdout, stderr) => {
16 | if (error) {
17 | console.error(`Error executing command: ${command}`);
18 | console.error(stderr);
19 | reject(error);
20 | } else {
21 | console.log(stdout);
22 | resolve(stdout);
23 | }
24 | });
25 | });
26 | };
27 |
28 | // Function to deploy the application
29 | const deploy = async () => {
30 | try {
31 | console.log('Starting deployment process...');
32 |
33 | // Step 1: Build the application
34 | console.log('Building the application...');
35 | await executeCommand('node scripts/build.js'); // Adjust the path to your build script
36 |
37 | // Step 2: Transfer files to the remote server
38 | console.log('Transferring files to the remote server...');
39 | await executeCommand(`rsync -avz --delete ${localBuildPath}/ ${remoteServer}:${remotePath}/`);
40 |
41 | // Step 3: Restart the server (if applicable)
42 | console.log('Restarting the server...');
43 | await executeCommand(`ssh ${remoteServer} 'pm2 restart your-app'`); // Adjust the command to restart your application
44 |
45 | console.log('Deployment completed successfully!');
46 | } catch (error) {
47 | console.error('Deployment failed:', error);
48 | }
49 | };
50 |
51 | // Execute the deploy function
52 | deploy();
53 |
--------------------------------------------------------------------------------
/src/frontend/scripts/build.js:
--------------------------------------------------------------------------------
1 | // src/frontend/scripts/build.js
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const { exec } = require('child_process');
6 |
7 | // Define paths
8 | const srcDir = path.join(__dirname, '../'); // Source directory
9 | const buildDir = path.join(__dirname, '../dist'); // Build output directory
10 |
11 | // Function to clean the build directory
12 | const cleanBuildDir = () => {
13 | if (fs.existsSync(buildDir)) {
14 | fs.rmdirSync(buildDir, { recursive: true });
15 | }
16 | fs.mkdirSync(buildDir);
17 | };
18 |
19 | // Function to copy static assets
20 | const copyAssets = () => {
21 | const assetsDir = path.join(srcDir, 'assets');
22 | if (fs.existsSync(assetsDir)) {
23 | fs.readdirSync(assetsDir).forEach(file => {
24 | const srcFile = path.join(assetsDir, file);
25 | const destFile = path.join(buildDir, file);
26 | fs.copyFileSync(srcFile, destFile);
27 | });
28 | }
29 | };
30 |
31 | // Function to build the frontend application
32 | const buildFrontend = () => {
33 | return new Promise((resolve, reject) => {
34 | exec('webpack --mode production', (error, stdout, stderr) => {
35 | if (error) {
36 | console.error(`Error during build: ${stderr}`);
37 | reject(error);
38 | } else {
39 | console.log(stdout);
40 | resolve();
41 | }
42 | });
43 | });
44 | };
45 |
46 | // Main build function
47 | const build = async () => {
48 | try {
49 | console.log('Cleaning build directory...');
50 | cleanBuildDir();
51 |
52 | console.log('Building frontend application...');
53 | await buildFrontend();
54 |
55 | console.log('Copying static assets...');
56 | copyAssets();
57 |
58 | console.log('Build completed successfully!');
59 | } catch (error) {
60 | console.error('Build failed:', error);
61 | }
62 | };
63 |
64 | // Run the build process
65 | build();
66 |
--------------------------------------------------------------------------------
/src/frontend/css/theme.css:
--------------------------------------------------------------------------------
1 | /* Base styles for both themes */
2 | body {
3 | font-family: Arial, sans-serif;
4 | transition: background-color 0.3s ease, color 0.3s ease;
5 | }
6 |
7 | /* Light Theme Styles */
8 | .light-mode {
9 | --background-color: #ffffff;
10 | --text-color: #000000;
11 | --primary-color: #007bff;
12 | --secondary-color: #6c757d;
13 | --border-color: #dee2e6;
14 | }
15 |
16 | .light-mode body {
17 | background-color: var(--background-color);
18 | color: var(--text-color);
19 | }
20 |
21 | .light-mode a {
22 | color: var(--primary-color);
23 | }
24 |
25 | .light-mode button {
26 | background-color: var(--primary-color);
27 | color: #ffffff;
28 | border: none;
29 | }
30 |
31 | .light-mode input,
32 | .light-mode textarea {
33 | background-color: #f8f9fa;
34 | color: var(--text-color);
35 | border: 1px solid var(--border-color);
36 | }
37 |
38 | /* Dark Theme Styles */
39 | .dark-mode {
40 | --background-color: #121212;
41 | --text-color: #ffffff;
42 | --primary-color: #bb86fc;
43 | --secondary-color: #3700b3;
44 | --border-color: #333333;
45 | }
46 |
47 | .dark-mode body {
48 | background-color: var(--background-color);
49 | color: var(--text-color);
50 | }
51 |
52 | .dark-mode a {
53 | color: var(--primary-color);
54 | }
55 |
56 | .dark-mode button {
57 | background-color: var(--primary-color);
58 | color: #ffffff;
59 | border: none;
60 | }
61 |
62 | .dark-mode input,
63 | .dark-mode textarea {
64 | background-color: #1e1e1e;
65 | color: var(--text-color);
66 | border: 1px solid var(--border-color);
67 | }
68 |
69 | /* Utility Classes */
70 | .theme-toggle {
71 | position: fixed;
72 | top: 20px;
73 | right: 20px;
74 | padding: 10px 15px;
75 | cursor: pointer;
76 | border: none;
77 | border-radius: 5px;
78 | background-color: var(--primary-color);
79 | color: #ffffff;
80 | transition: background-color 0.3s ease;
81 | }
82 |
83 | .theme-toggle:hover {
84 | background-color: var(--secondary-color);
85 | }
86 |
--------------------------------------------------------------------------------
/src/backend/services/analyticsService.js:
--------------------------------------------------------------------------------
1 | // src/backend/services/analyticsService.js
2 | const Transaction = require('../models/transactionModel');
3 | const User = require('../models/userModel');
4 | const Charity = require('../models/charityModel');
5 | const Analytics = require('../models/analyticsModel');
6 |
7 | // Get overall analytics data
8 | const getAnalyticsData = async () => {
9 | const totalUsers = await User.countDocuments();
10 | const totalPayments = await Transaction.countDocuments();
11 | const totalPaymentAmount = await Transaction.aggregate([
12 | { $group: { _id: null, total: { $sum: '$amount' } } }
13 | ]);
14 | const totalCharities = await Charity.countDocuments();
15 |
16 | return {
17 | totalUsers,
18 | totalPayments,
19 | totalPaymentAmount: totalPaymentAmount[0]?.total || 0,
20 | totalCharities,
21 | };
22 | };
23 |
24 | // Get payment analytics for a specific user
25 | const getUser PaymentAnalytics = async (userId) => {
26 | // Validate input
27 | if (!userId) {
28 | throw new Error('User ID is required.');
29 | }
30 |
31 | const totalPayments = await Transaction.countDocuments({ userId });
32 | const totalPaymentAmount = await Transaction.aggregate([
33 | { $match: { userId } },
34 | { $group: { _id: null, total: { $sum: '$amount' } } }
35 | ]);
36 |
37 | return {
38 | totalPayments,
39 | totalPaymentAmount: totalPaymentAmount[0]?.total || 0,
40 | };
41 | };
42 |
43 | // Get charity analytics
44 | const getCharityAnalytics = async () => {
45 | const totalCharities = await Charity.countDocuments();
46 | const totalDonations = await Transaction.aggregate([
47 | { $group: { _id: null, total: { $sum: '$amount' } } }
48 | ]);
49 |
50 | return {
51 | totalCharities,
52 | totalDonations: totalDonations[0]?.total || 0,
53 | };
54 | };
55 |
56 | // Export the analytics service functions
57 | module.exports = {
58 | getAnalyticsData,
59 | getUser PaymentAnalytics,
60 | getCharityAnalytics,
61 | };
62 |
--------------------------------------------------------------------------------
/ai/trainingData/feedbackData.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "userId": "user1",
4 | "feedback": "I absolutely love this product! It has changed my life for the better.",
5 | "rating": 5,
6 | "timestamp": "2023-10-01T10:00:00Z"
7 | },
8 | {
9 | "userId": "user2",
10 | "feedback": "The service was okay, but I expected more features.",
11 | "rating": 3,
12 | "timestamp": "2023-10-02T11:15:00Z"
13 | },
14 | {
15 | "userId": "user3",
16 | "feedback": "I had a terrible experience. The product did not work as advertised.",
17 | "rating": 1,
18 | "timestamp": "2023-10-03T12:30:00Z"
19 | },
20 | {
21 | "userId": "user4",
22 | "feedback": "Great value for the price! Highly recommend it to others.",
23 | "rating": 4,
24 | "timestamp": "2023-10-04T09:45:00Z"
25 | },
26 | {
27 | "userId": "user5",
28 | "feedback": "Not satisfied with the customer support. They were unhelpful.",
29 | "rating": 2,
30 | "timestamp": "2023-10-05T14:20:00Z"
31 | },
32 | {
33 | "userId": "user6",
34 | "feedback": "This is the best purchase I've made this year! Fantastic quality.",
35 | "rating": 5,
36 | "timestamp": "2023-10-06T08:00:00Z"
37 | },
38 | {
39 | "userId": "user7",
40 | "feedback": "I like the product, but it could use some improvements.",
41 | "rating": 3,
42 | "timestamp": "2023-10-07T15:30:00Z"
43 | },
44 | {
45 | "userId": "user8",
46 | "feedback": "Absolutely terrible! I want a refund.",
47 | "rating": 1,
48 | "timestamp": "2023-10-08T10:10:00Z"
49 | },
50 | {
51 | "userId": "user9",
52 | "feedback": "Decent product, but the delivery was late.",
53 | "rating": 3,
54 | "timestamp": "2023-10-09T13:25:00Z"
55 | },
56 | {
57 | "userId": "user10",
58 | "feedback": "I am very happy with my purchase. Will buy again!",
59 | "rating": 5,
60 | "timestamp": "2023-10-10T16:00:00Z"
61 | }
62 | ]
63 |
--------------------------------------------------------------------------------
/blockchain/oracles/eventOracle.js:
--------------------------------------------------------------------------------
1 | const axios = require('axios');
2 | const { EventEmitter } = require('events');
3 |
4 | class EventOracle extends EventEmitter {
5 | constructor(apiUrl) {
6 | super();
7 | this.apiUrl = apiUrl;
8 | this.events = [];
9 | this.updateInterval = 30000; // Update every 30 seconds
10 | this.startEventFeed();
11 | }
12 |
13 | // Function to fetch the latest events from the API
14 | async fetchEvents() {
15 | try {
16 | const response = await axios.get(this.apiUrl);
17 | const newEvents = this.extractEvents(response.data);
18 | this.processEvents(newEvents);
19 | } catch (error) {
20 | console.error('Error fetching events:', error.message);
21 | }
22 | }
23 |
24 | // Function to extract events from the API response
25 | extractEvents(data) {
26 | // Assuming the API returns a JSON object with an 'events' array
27 | // Modify this according to the actual API response structure
28 | return data.events || [];
29 | }
30 |
31 | // Function to process new events
32 | processEvents(newEvents) {
33 | newEvents.forEach(event => {
34 | if (!this.events.includes(event.id)) { // Check for duplicates
35 | this.events.push(event.id);
36 | this.emit('eventReceived', event); // Emit event when a new event is received
37 | }
38 | });
39 | }
40 |
41 | // Function to start the event feed
42 | startEventFeed() {
43 | this.fetchEvents(); // Initial fetch
44 | setInterval(() => {
45 | this.fetchEvents();
46 | }, this.updateInterval);
47 | }
48 | }
49 |
50 | // Example usage
51 | const eventOracle = new EventOracle('https://api.example.com/events');
52 |
53 | eventOracle.on('eventReceived', (event) => {
54 | console.log(`New event received: ${JSON.stringify(event)}`);
55 | // Here you can add logic to interact with your blockchain smart contracts
56 | });
57 |
58 | // Export the EventOracle class
59 | module.exports = EventOracle;
60 |
--------------------------------------------------------------------------------
/src/frontend/css/styles.css:
--------------------------------------------------------------------------------
1 | /* General Styles */
2 | body {
3 | margin: 0;
4 | padding: 0;
5 | font-family: 'Arial', sans-serif;
6 | background: linear-gradient(to right, #f0f4f8, #e0e7ff);
7 | color: #333;
8 | }
9 |
10 | /* Header Styles */
11 | header {
12 | background: rgba(0, 123, 255, 0.8);
13 | backdrop-filter: blur(10px);
14 | padding: 60px 20px;
15 | text-align: center;
16 | }
17 |
18 | header h1 {
19 | font-size: 3rem;
20 | margin-bottom: 10px;
21 | }
22 |
23 | header p {
24 | font-size: 1.5rem;
25 | }
26 |
27 | /* Main Content Styles */
28 | .container {
29 | max-width: 1200px;
30 | margin: auto;
31 | padding: 20px;
32 | }
33 |
34 | h2 {
35 | font-size: 2.5rem;
36 | margin-bottom: 20px;
37 | text-align: center;
38 | }
39 |
40 | /* Charity Card Styles */
41 | .charity-card {
42 | background: white;
43 | border-radius: 10px;
44 | box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
45 | margin: 15px;
46 | padding: 20px;
47 | transition: transform 0.3s, box-shadow 0.3s;
48 | }
49 |
50 | .charity-card:hover {
51 | transform: translateY(-5px);
52 | box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
53 | }
54 |
55 | .charity-card h3 {
56 | font-size: 1.8rem;
57 | margin-bottom: 10px;
58 | }
59 |
60 | .charity-card p {
61 | font-size: 1rem;
62 | color: #666;
63 | }
64 |
65 | /* Footer Styles */
66 | footer {
67 | background: rgba(0, 0, 0, 0.8);
68 | color: white;
69 | padding: 20px 0;
70 | text-align: center;
71 | }
72 |
73 | footer p {
74 | margin: 0;
75 | }
76 |
77 | footer a {
78 | color: white;
79 | text-decoration: none;
80 | margin: 0 10px;
81 | }
82 |
83 | footer a:hover {
84 | text-decoration: underline;
85 | }
86 |
87 | /* Responsive Styles */
88 | @media (max-width: 768px) {
89 | header h1 {
90 | font-size: 2.5rem;
91 | }
92 |
93 | header p {
94 | font-size: 1.2rem;
95 | }
96 |
97 | h2 {
98 | font-size: 2rem;
99 | }
100 |
101 | .charity-card {
102 | margin: 10px;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/src/frontend/scripts/deploy.js:
--------------------------------------------------------------------------------
1 | // src/frontend/scripts/deploy.js
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const { exec } = require('child_process');
6 |
7 | // Define paths
8 | const buildDir = path.join(__dirname, '../dist'); // Build output directory
9 | const deploymentDir = path.join(__dirname, '../deployment'); // Deployment directory
10 |
11 | // Function to clean the deployment directory
12 | const cleanDeploymentDir = () => {
13 | if (fs.existsSync(deploymentDir)) {
14 | fs.rmdirSync(deploymentDir, { recursive: true });
15 | }
16 | fs.mkdirSync(deploymentDir);
17 | };
18 |
19 | // Function to copy build files to the deployment directory
20 | const copyBuildFiles = () => {
21 | fs.readdirSync(buildDir).forEach(file => {
22 | const srcFile = path.join(buildDir, file);
23 | const destFile = path.join(deploymentDir, file);
24 | fs.copyFileSync(srcFile, destFile);
25 | });
26 | };
27 |
28 | // Function to deploy the application (example using a hypothetical deployment command)
29 | const deployApplication = () => {
30 | return new Promise((resolve, reject) => {
31 | // Replace this command with your actual deployment command
32 | exec('your-deployment-command', (error, stdout, stderr) => {
33 | if (error) {
34 | console.error(`Error during deployment: ${stderr}`);
35 | reject(error);
36 | } else {
37 | console.log(stdout);
38 | resolve();
39 | }
40 | });
41 | });
42 | };
43 |
44 | // Main deployment function
45 | const deploy = async () => {
46 | try {
47 | console.log('Cleaning deployment directory...');
48 | cleanDeploymentDir();
49 |
50 | console.log('Copying build files to deployment directory...');
51 | copyBuildFiles();
52 |
53 | console.log('Deploying application...');
54 | await deployApplication();
55 |
56 | console.log('Deployment completed successfully!');
57 | } catch (error) {
58 | console.error('Deployment failed:', error);
59 | }
60 | };
61 |
62 | // Run the deployment process
63 | deploy();
64 |
--------------------------------------------------------------------------------
/src/backend/routes/fraudRoutes.js:
--------------------------------------------------------------------------------
1 | // fraudRoutes.js
2 |
3 | const express = require('express');
4 | const router = express.Router();
5 | const FraudDetectionController = require('../controllers/fraudDetectionController');
6 | const { authMiddleware } = require('../middleware/authMiddleware');
7 | const { validateFraudReportInput } = require('../middleware/inputValidationMiddleware');
8 |
9 | // Route to report potential fraud
10 | router.post('/report', authMiddleware, validateFraudReportInput, async (req, res) => {
11 | try {
12 | await FraudDetectionController.reportFraud(req, res);
13 | } catch (error) {
14 | res.status(500).json({ success: false, message: 'Error reporting fraud' });
15 | }
16 | });
17 |
18 | // Route to analyze recent transactions for potential fraud
19 | router.get('/analyze', authMiddleware, async (req, res) => {
20 | try {
21 | await FraudDetectionController.analyzeTransactions(req, res);
22 | } catch (error) {
23 | res.status(500).json({ success: false, message: 'Error analyzing transactions' });
24 | }
25 | });
26 |
27 | // Route to get fraud reports for a user
28 | router.get('/reports', authMiddleware, async (req, res) => {
29 | try {
30 | await FraudDetectionController.getUser FraudReports(req, res);
31 | } catch (error) {
32 | res.status(500).json({ success: false, message: 'Error fetching fraud reports' });
33 | }
34 | });
35 |
36 | // Route to review and take action on a fraud alert
37 | router.put('/alerts/:alertId', authMiddleware, async (req, res) => {
38 | try {
39 | await FraudDetectionController.reviewFraudAlert(req, res);
40 | } catch (error) {
41 | res.status(500).json({ success: false, message: 'Error reviewing fraud alert' });
42 | }
43 | });
44 |
45 | // Route to get all fraud alerts (admin only)
46 | router.get('/alerts', authMiddleware, async (req, res) => {
47 | try {
48 | // Assuming there's an admin check in the middleware
49 | await FraudDetectionController.getAllFraudAlerts(req, res);
50 | } catch (error) {
51 | res.status(500).json({ success: false, message: 'Error fetching fraud alerts' });
52 | }
53 | });
54 |
55 | module.exports = router;
56 |
--------------------------------------------------------------------------------
/blockchain/smartContracts/analyticsContract.py:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.0;
3 |
4 | import "@openzeppelin/contracts/access/Ownable.sol";
5 | import "@openzeppelin/contracts/utils/math/SafeMath.sol";
6 |
7 | contract AnalyticsContract is Ownable {
8 | using SafeMath for uint256;
9 |
10 | // Struct to represent donation analytics
11 | struct DonationData {
12 | uint256 totalDonations;
13 | uint256 donationCount;
14 | }
15 |
16 | // Mapping to store analytics data for each charity
17 | mapping(string => DonationData) private charityAnalytics;
18 |
19 | // Mapping to store analytics data for each user
20 | mapping(address => DonationData) private userAnalytics;
21 |
22 | // Event to log donations for analytics
23 | event DonationLogged(address indexed donor, string indexed charityId, uint256 amount);
24 |
25 | // Function to log a donation
26 | function logDonation(address donor, string memory charityId, uint256 amount) external onlyOwner {
27 | require(amount > 0, "Donation must be greater than zero");
28 |
29 | // Update charity analytics
30 | charityAnalytics[charityId].totalDonations = charityAnalytics[charityId].totalDonations.add(amount);
31 | charityAnalytics[charityId].donationCount = charityAnalytics[charityId].donationCount.add(1);
32 |
33 | // Update user analytics
34 | userAnalytics[donor].totalDonations = userAnalytics[donor].totalDonations.add(amount);
35 | userAnalytics[donor].donationCount = userAnalytics[donor].donationCount.add(1);
36 |
37 | emit DonationLogged(donor, charityId, amount);
38 | }
39 |
40 | // Function to get total donations for a charity
41 | function getCharityAnalytics(string memory charityId) public view returns (uint256 totalDonations, uint256 donationCount) {
42 | DonationData memory data = charityAnalytics[charityId];
43 | return (data.totalDonations, data.donationCount);
44 | }
45 |
46 | // Function to get total donations for a user
47 | function getUser Analytics(address user) public view returns (uint256 totalDonations, uint256 donationCount) {
48 | DonationData memory data = userAnalytics[user];
49 | return (data.totalDonations, data.donationCount);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/backend/services/notificationService.js:
--------------------------------------------------------------------------------
1 | // src/backend/services/notificationService.js
2 | const Notification = require('../models/notificationModel');
3 |
4 | // Send a notification
5 | const sendNotification = async (userId, message) => {
6 | // Validate input
7 | if (!userId || !message) {
8 | throw new Error('User ID and message are required.');
9 | }
10 |
11 | // Create a new notification
12 | const notification = new Notification({
13 | userId,
14 | message,
15 | });
16 |
17 | // Save the notification to the database
18 | await notification.save();
19 |
20 | return notification;
21 | };
22 |
23 | // Get notifications for a specific user
24 | const getUser Notifications = async (userId) => {
25 | // Validate input
26 | if (!userId) {
27 | throw new Error('User ID is required.');
28 | }
29 |
30 | // Retrieve notifications for the user
31 | const notifications = await Notification.find({ userId }).sort({ createdAt: -1 });
32 | return notifications;
33 | };
34 |
35 | // Mark a notification as read
36 | const markNotificationAsRead = async (notificationId) => {
37 | // Validate input
38 | if (!notificationId) {
39 | throw new Error('Notification ID is required.');
40 | }
41 |
42 | // Find the notification and mark it as read
43 | const notification = await Notification.findById(notificationId);
44 | if (!notification) {
45 | throw new Error('Notification not found.');
46 | }
47 |
48 | notification.markAsRead(); // Call the method defined in the model
49 | return notification;
50 | };
51 |
52 | // Delete a notification
53 | const deleteNotification = async (notificationId) => {
54 | // Validate input
55 | if (!notificationId) {
56 | throw new Error('Notification ID is required.');
57 | }
58 |
59 | // Delete the notification
60 | const notification = await Notification.findByIdAndDelete(notificationId);
61 | if (!notification) {
62 | throw new Error('Notification not found.');
63 | }
64 |
65 | return notification;
66 | };
67 |
68 | // Export the notification service functions
69 | module.exports = {
70 | sendNotification,
71 | getUser Notifications,
72 | markNotificationAsRead,
73 | deleteNotification,
74 | };
75 |
--------------------------------------------------------------------------------
/src/backend/services/charityService.js:
--------------------------------------------------------------------------------
1 | // src/backend/services/charityService.js
2 | const Charity = require('../models/charityModel');
3 |
4 | // Create a new charity
5 | const createCharity = async (name, description) => {
6 | // Validate input
7 | if (!name || !description) {
8 | throw new Error('Name and description are required.');
9 | }
10 |
11 | // Create a new charity
12 | const charity = new Charity({
13 | name,
14 | description,
15 | });
16 |
17 | // Save the charity to the database
18 | await charity.save();
19 |
20 | return charity;
21 | };
22 |
23 | // Get all charities
24 | const getAllCharities = async () => {
25 | // Retrieve all charities from the database
26 | const charities = await Charity.find();
27 | return charities;
28 | };
29 |
30 | // Get a charity by ID
31 | const getCharityById = async (charityId) => {
32 | // Validate input
33 | if (!charityId) {
34 | throw new Error('Charity ID is required.');
35 | }
36 |
37 | // Retrieve the charity by ID
38 | const charity = await Charity.findById(charityId);
39 | if (!charity) {
40 | throw new Error('Charity not found.');
41 | }
42 |
43 | return charity;
44 | };
45 |
46 | // Update a charity by ID
47 | const updateCharity = async (charityId, updates) => {
48 | // Validate input
49 | if (!charityId || !updates) {
50 | throw new Error('Charity ID and updates are required.');
51 | }
52 |
53 | // Update the charity
54 | const charity = await Charity.findByIdAndUpdate(charityId, updates, { new: true });
55 | if (!charity) {
56 | throw new Error('Charity not found.');
57 | }
58 |
59 | return charity;
60 | };
61 |
62 | // Delete a charity by ID
63 | const deleteCharity = async (charityId) => {
64 | // Validate input
65 | if (!charityId) {
66 | throw new Error('Charity ID is required.');
67 | }
68 |
69 | // Delete the charity
70 | const charity = await Charity.findByIdAndDelete(charityId);
71 | if (!charity) {
72 | throw new Error('Charity not found.');
73 | }
74 |
75 | return charity;
76 | };
77 |
78 | // Export the charity service functions
79 | module.exports = {
80 | createCharity,
81 | getAllCharities,
82 | getCharityById,
83 | updateCharity,
84 | deleteCharity,
85 | };
86 |
--------------------------------------------------------------------------------
/src/backend/routes/eventRoutes.js:
--------------------------------------------------------------------------------
1 | // eventRoutes.js
2 |
3 | const express = require('express');
4 | const router = express.Router();
5 | const EventController = require('../controllers/eventController');
6 | const { authMiddleware } = require('../middleware/authMiddleware');
7 | const { validateEventInput, validateRegistrationInput } = require('../middleware/inputValidationMiddleware');
8 |
9 | // Route to create a new event
10 | router.post('/events', authMiddleware, validateEventInput, async (req, res) => {
11 | try {
12 | await EventController.createEvent(req, res);
13 | } catch (error) {
14 | res.status(500).json({ success: false, message: 'Error creating event' });
15 | }
16 | });
17 |
18 | // Route to get all events
19 | router.get('/events', authMiddleware, async (req, res) => {
20 | try {
21 | await EventController.getAllEvents(req, res);
22 | } catch (error) {
23 | res.status(500).json({ success: false, message: 'Error fetching events' });
24 | }
25 | });
26 |
27 | // Route to get a single event by ID
28 | router.get('/events/:eventId', authMiddleware, async (req, res) => {
29 | try {
30 | await EventController.getEventById(req, res);
31 | } catch (error) {
32 | res.status(500).json({ success: false, message: 'Error fetching event' });
33 | }
34 | });
35 |
36 | // Route to register for an event
37 | router.post('/events/:eventId/register', authMiddleware, validateRegistrationInput, async (req, res) => {
38 | try {
39 | await EventController.registerForEvent(req, res);
40 | } catch (error) {
41 | res.status(500).json({ success: false, message: 'Error registering for event' });
42 | }
43 | });
44 |
45 | // Route to get registrations for a specific event
46 | router.get('/events/:eventId/registrations', authMiddleware, async (req, res) => {
47 | try {
48 | await EventController.getEventRegistrations(req, res);
49 | } catch (error) {
50 | res.status(500).json({ success: false, message: 'Error fetching event registrations' });
51 | }
52 | });
53 |
54 | // Route to cancel registration for an event
55 | router.delete('/events/:eventId/register', authMiddleware, async (req, res) => {
56 | try {
57 | await EventController.cancelRegistration(req, res);
58 | } catch (error) {
59 | res.status(500).json({ success: false, message: 'Error canceling registration' });
60 | }
61 | });
62 |
63 | module.exports = router;
64 |
--------------------------------------------------------------------------------
/src/backend/services/userService.js:
--------------------------------------------------------------------------------
1 | // src/backend/services/userService.js
2 | const User = require('../models/userModel');
3 | const bcrypt = require('bcrypt');
4 | const jwt = require('jsonwebtoken');
5 |
6 | // Register a new user
7 | const registerUser = async (username, password, email) => {
8 | // Validate input
9 | if (!username || !password || !email) {
10 | throw new Error('Username, password, and email are required.');
11 | }
12 |
13 | // Check if the username or email already exists
14 | const existingUser = await User.findOne({ $or: [{ username }, { email }] });
15 | if (existingUser ) {
16 | throw new Error('Username or email already exists.');
17 | }
18 |
19 | // Hash the password
20 | const hashedPassword = await bcrypt.hash(password, 10);
21 |
22 | // Create a new user
23 | const newUser = new User({
24 | username,
25 | password: hashedPassword,
26 | email,
27 | });
28 |
29 | // Save the user to the database
30 | await newUser .save();
31 |
32 | return newUser ;
33 | };
34 |
35 | // Log in a user
36 | const loginUser = async (username, password) => {
37 | // Validate input
38 | if (!username || !password) {
39 | throw new Error('Username and password are required.');
40 | }
41 |
42 | // Find the user by username
43 | const user = await User.findOne({ username });
44 | if (!user) {
45 | throw new Error('Invalid username or password.');
46 | }
47 |
48 | // Compare the provided password with the stored hashed password
49 | const isMatch = await bcrypt.compare(password, user.password);
50 | if (!isMatch) {
51 | throw new Error('Invalid username or password.');
52 | }
53 |
54 | // Generate a JWT token
55 | const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '1h' });
56 |
57 | return { user, token };
58 | };
59 |
60 | // Get user information by user ID
61 | const getUser Info = async (userId) => {
62 | // Validate input
63 | if (!userId) {
64 | throw new Error('User ID is required.');
65 | }
66 |
67 | // Retrieve the user by ID, excluding the password
68 | const user = await User.findById(userId).select('-password');
69 | if (!user) {
70 | throw new Error('User not found.');
71 | }
72 |
73 | return user;
74 | };
75 |
76 | // Export the user service functions
77 | module.exports = {
78 | registerUser ,
79 | loginUser ,
80 | getUser Info,
81 | };
82 |
--------------------------------------------------------------------------------
/blockchain/smartContracts/aiContract.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.0;
3 |
4 | contract AIContract {
5 | struct Model {
6 | string name;
7 | string description;
8 | address owner;
9 | string modelURI; // URI to the model's metadata or location
10 | bool isActive;
11 | }
12 |
13 | mapping(uint256 => Model) public models; // Mapping of model ID to Model
14 | mapping(address => uint256[]) public userModels; // Mapping of user address to their model IDs
15 | uint256 public modelCount; // Counter for the number of models
16 |
17 | event ModelCreated(uint256 indexed modelId, string name, address indexed owner);
18 | event ModelUpdated(uint256 indexed modelId, string name, bool isActive);
19 | event ModelDeleted(uint256 indexed modelId);
20 |
21 | modifier onlyOwner(uint256 modelId) {
22 | require(msg.sender == models[modelId].owner, "Not the model owner");
23 | _;
24 | }
25 |
26 | // Function to create a new AI model
27 | function createModel(string memory name, string memory description, string memory modelURI) public {
28 | modelCount++;
29 | models[modelCount] = Model(name, description, msg.sender, modelURI, true);
30 | userModels[msg.sender].push(modelCount);
31 | emit ModelCreated(modelCount, name, msg.sender);
32 | }
33 |
34 | // Function to update an existing AI model
35 | function updateModel(uint256 modelId, string memory name, string memory description, bool isActive) public onlyOwner(modelId) {
36 | Model storage model = models[modelId];
37 | model.name = name;
38 | model.description = description;
39 | model.isActive = isActive;
40 | emit ModelUpdated(modelId, name, isActive);
41 | }
42 |
43 | // Function to delete an AI model
44 | function deleteModel(uint256 modelId) public onlyOwner(modelId) {
45 | delete models[modelId];
46 | emit ModelDeleted(modelId);
47 | }
48 |
49 | // Function to get model details
50 | function getModel(uint256 modelId) public view returns (string memory name, string memory description, address owner, string memory modelURI, bool isActive) {
51 | Model memory model = models[modelId];
52 | return (model.name, model.description, model.owner, model.modelURI, model.isActive);
53 | }
54 |
55 | // Function to get models created by a user
56 | function getUser Models(address user) public view returns (uint256[] memory) {
57 | return userModels[user];
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/frontend/js/analytics.js:
--------------------------------------------------------------------------------
1 | // src/frontend/js/analytics.js
2 |
3 | // Function to fetch overall analytics data
4 | const fetchOverallAnalytics = async () => {
5 | try {
6 | const response = await fetch('/api/analytics', {
7 | method: 'GET',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | },
11 | });
12 |
13 | if (!response.ok) {
14 | throw new Error('Failed to fetch overall analytics');
15 | }
16 |
17 | const analyticsData = await response.json();
18 | return analyticsData; // Return the overall analytics data
19 | } catch (error) {
20 | console.error('Error fetching overall analytics:', error);
21 | throw new Error('Failed to load overall analytics. Please try again later.');
22 | }
23 | };
24 |
25 | // Function to fetch user-specific analytics
26 | const fetchUser Analytics = async (userId) => {
27 | try {
28 | const response = await fetch(`/api/analytics/user/${userId}`, {
29 | method: 'GET',
30 | headers: {
31 | 'Content-Type': 'application/json',
32 | },
33 | });
34 |
35 | if (!response.ok) {
36 | throw new Error('Failed to fetch user analytics');
37 | }
38 |
39 | const userAnalytics = await response.json();
40 | return userAnalytics; // Return the user-specific analytics data
41 | } catch (error) {
42 | console.error('Error fetching user analytics:', error);
43 | throw new Error('Failed to load user analytics. Please try again later.');
44 | }
45 | };
46 |
47 | // Function to fetch charity analytics
48 | const fetchCharityAnalytics = async () => {
49 | try {
50 | const response = await fetch('/api/analytics/charity', {
51 | method: 'GET',
52 | headers: {
53 | 'Content-Type': 'application/json',
54 | },
55 | });
56 |
57 | if (!response.ok) {
58 | throw new Error('Failed to fetch charity analytics');
59 | }
60 |
61 | const charityAnalytics = await response.json();
62 | return charityAnalytics; // Return the charity analytics data
63 | } catch (error) {
64 | console.error('Error fetching charity analytics:', error);
65 | throw new Error('Failed to load charity analytics. Please try again later.');
66 | }
67 | };
68 |
69 | // Exporting the analytics functions
70 | export {
71 | fetchOverallAnalytics,
72 | fetchUser Analytics,
73 | fetchCharityAnalytics,
74 | };
75 |
--------------------------------------------------------------------------------
/ai/communityEngagementAnalysis.js:
--------------------------------------------------------------------------------
1 | // communityEngagementAnalysis.js
2 |
3 | // Sample data structure for community members and events
4 | const members = [
5 | { id: 1, name: 'Alice', contributions: 5, isActive: true },
6 | { id: 2, name: 'Bob', contributions: 3, isActive: true },
7 | { id: 3, name: 'Charlie', contributions: 0, isActive: false },
8 | ];
9 |
10 | const events = [
11 | { id: 1, title: 'Community Meetup', participants: [1, 2], date: '2023-10-01' },
12 | { id: 2, title: 'Online Workshop', participants: [1], date: '2023-10-15' },
13 | { id: 3, title: 'Charity Event', participants: [], date: '2023-10-20' },
14 | ];
15 |
16 | /**
17 | * Calculate the total number of active members in the community.
18 | * @returns {number} The count of active members.
19 | */
20 | function getActiveMemberCount() {
21 | return members.filter(member => member.isActive).length;
22 | }
23 |
24 | /**
25 | * Calculate the total contributions made by all members.
26 | * @returns {number} The total contributions.
27 | */
28 | function getTotalContributions() {
29 | return members.reduce((total, member) => total + member.contributions, 0);
30 | }
31 |
32 | /**
33 | * Calculate the participation rate for events.
34 | * @returns {Object} An object containing event participation rates.
35 | */
36 | function getEventParticipationRates() {
37 | const participationRates = events.map(event => {
38 | const totalParticipants = event.participants.length;
39 | const participationRate = totalParticipants / members.length; // Assuming all members can participate
40 | return {
41 | eventId: event.id,
42 | title: event.title,
43 | participationRate: participationRate,
44 | };
45 | });
46 | return participationRates;
47 | }
48 |
49 | /**
50 | * Get a summary of community engagement metrics.
51 | * @returns {Object} An object containing various engagement metrics.
52 | */
53 | function getEngagementSummary() {
54 | const activeMemberCount = getActiveMemberCount();
55 | const totalContributions = getTotalContributions();
56 | const eventParticipationRates = getEventParticipationRates();
57 |
58 | return {
59 | activeMemberCount,
60 | totalContributions,
61 | eventParticipationRates,
62 | };
63 | }
64 |
65 | // Example usage
66 | const engagementSummary = getEngagementSummary();
67 | console.log('Community Engagement Summary:', engagementSummary);
68 |
69 | module.exports = {
70 | getActiveMemberCount,
71 | getTotalContributions,
72 | getEventParticipationRates,
73 | getEngagementSummary,
74 | };
75 |
--------------------------------------------------------------------------------
/src/frontend/components/TransactionList.js:
--------------------------------------------------------------------------------
1 | // src/frontend/components/TransactionList.js
2 |
3 | import React, { useEffect, useState } from 'react';
4 | import PropTypes from 'prop-types';
5 |
6 | const TransactionList = ({ userId }) => {
7 | const [transactions, setTransactions] = useState([]);
8 | const [loading, setLoading] = useState(true);
9 | const [error, setError] = useState(null);
10 |
11 | // Function to fetch transactions for the user
12 | const fetchTransactions = async () => {
13 | try {
14 | const response = await fetch(`/api/users/${userId}/transactions`);
15 | if (!response.ok) {
16 | throw new Error('Failed to fetch transactions');
17 | }
18 | const data = await response.json();
19 | setTransactions(data);
20 | } catch (err) {
21 | setError(err.message);
22 | } finally {
23 | setLoading(false);
24 | }
25 | };
26 |
27 | useEffect(() => {
28 | fetchTransactions();
29 | }, [userId]);
30 |
31 | if (loading) {
32 | return Loading transactions...
;
33 | }
34 |
35 | if (error) {
36 | return {error}
;
37 | }
38 |
39 | return (
40 |
41 |
Transaction History
42 |
43 |
44 |
45 | | Date |
46 | Amount |
47 | Status |
48 |
49 |
50 |
51 | {transactions.length > 0 ? (
52 | transactions.map((transaction) => (
53 |
54 | | {new Date(transaction.date).toLocaleDateString()} |
55 | ${transaction.amount.toFixed(2)} |
56 | {transaction.status} |
57 |
58 | ))
59 | ) : (
60 |
61 | | No transactions found. |
62 |
63 | )}
64 |
65 |
66 |
67 | );
68 | };
69 |
70 | TransactionList.propTypes = {
71 | userId: PropTypes.string.isRequired,
72 | };
73 |
74 | export default TransactionList;
75 |
--------------------------------------------------------------------------------
/ai/sentimentAnalysis.js:
--------------------------------------------------------------------------------
1 | const axios = require('axios');
2 | const { SentimentAnalyzer } = require('natural');
3 | const { PorterStemmer } = require('natural');
4 |
5 | class SentimentAnalysis {
6 | constructor(apiUrl) {
7 | this.apiUrl = apiUrl;
8 | this.analyzer = new SentimentAnalyzer('English', PorterStemmer, 'afinn');
9 | }
10 |
11 | // Function to fetch user feedback data
12 | async fetchUser Feedback() {
13 | try {
14 | const response = await axios.get(this.apiUrl);
15 | return response.data.feedback; // Assuming the API returns an array of feedback
16 | } catch (error) {
17 | console.error('Error fetching user feedback:', error.message);
18 | return [];
19 | }
20 | }
21 |
22 | // Function to analyze sentiment of feedback
23 | analyzeSentiment(feedback) {
24 | return feedback.map(item => {
25 | const score = this.analyzer.getSentiment(item.text.split(' '));
26 | let sentiment = 'neutral';
27 | if (score > 0) {
28 | sentiment = 'positive';
29 | } else if (score < 0) {
30 | sentiment = 'negative';
31 | }
32 | return {
33 | text: item.text,
34 | score: score,
35 | sentiment: sentiment,
36 | };
37 | });
38 | }
39 |
40 | // Function to generate sentiment report
41 | generateReport(sentimentResults) {
42 | const report = {
43 | totalFeedback: sentimentResults.length,
44 | positive: sentimentResults.filter(result => result.sentiment === 'positive').length,
45 | negative: sentimentResults.filter(result => result.sentiment === 'negative').length,
46 | neutral: sentimentResults.filter(result => result.sentiment === 'neutral').length,
47 | };
48 | console.log('Sentiment Report:', report);
49 | return report;
50 | }
51 |
52 | // Main function to execute sentiment analysis
53 | async run() {
54 | const feedback = await this.fetchUser Feedback();
55 | const sentimentResults = this.analyzeSentiment(feedback);
56 | this.generateReport(sentimentResults);
57 | }
58 | }
59 |
60 | // Example usage
61 | const apiUrl = 'https://api.example.com/user-feedback'; // Replace with actual API
62 | const sentimentAnalysis = new SentimentAnalysis(apiUrl);
63 | sentimentAnalysis.run()
64 | .catch(error => {
65 | console.error('Error in sentiment analysis process:', error);
66 | });
67 |
68 | // Export the SentimentAnalysis class
69 | module.exports = SentimentAnalysis;
70 |
--------------------------------------------------------------------------------
/src/backend/routes/communityRoutes.js:
--------------------------------------------------------------------------------
1 | // communityRoutes.js
2 |
3 | const express = require('express');
4 | const router = express.Router();
5 | const CommunityController = require('../controllers/communityController');
6 | const { authMiddleware } = require('../middleware/authMiddleware');
7 | const { validatePostInput, validateCommentInput } = require('../middleware/inputValidationMiddleware');
8 |
9 | // Route to create a new post
10 | router.post('/posts', authMiddleware, validatePostInput, async (req, res) => {
11 | try {
12 | await CommunityController.createPost(req, res);
13 | } catch (error) {
14 | res.status(500).json({ success: false, message: 'Error creating post' });
15 | }
16 | });
17 |
18 | // Route to get all posts
19 | router.get('/posts', authMiddleware, async (req, res) => {
20 | try {
21 | await CommunityController.getAllPosts(req, res);
22 | } catch (error) {
23 | res.status(500).json({ success: false, message: 'Error fetching posts' });
24 | }
25 | });
26 |
27 | // Route to get a single post by ID
28 | router.get('/posts/:postId', authMiddleware, async (req, res) => {
29 | try {
30 | await CommunityController.getPostById(req, res);
31 | } catch (error) {
32 | res.status(500).json({ success: false, message: 'Error fetching post' });
33 | }
34 | });
35 |
36 | // Route to create a comment on a post
37 | router.post('/posts/:postId/comments', authMiddleware, validateCommentInput, async (req, res) => {
38 | try {
39 | await CommunityController.createComment(req, res);
40 | } catch (error) {
41 | res.status(500).json({ success: false, message: 'Error creating comment' });
42 | }
43 | });
44 |
45 | // Route to get comments for a specific post
46 | router.get('/posts/:postId/comments', authMiddleware, async (req, res) => {
47 | try {
48 | await CommunityController.getCommentsForPost(req, res);
49 | } catch (error) {
50 | res.status(500).json({ success: false, message: 'Error fetching comments' });
51 | }
52 | });
53 |
54 | // Route to like a post
55 | router.post('/posts/:postId/like', authMiddleware, async (req, res) => {
56 | try {
57 | await CommunityController.likePost(req, res);
58 | } catch (error) {
59 | res.status(500).json({ success: false, message: 'Error liking post' });
60 | }
61 | });
62 |
63 | // Route to dislike a post
64 | router.post('/posts/:postId/dislike', authMiddleware, async (req, res) => {
65 | try {
66 | await CommunityController.dislikePost(req, res);
67 | } catch (error) {
68 | res.status(500).json({ success: false, message: 'Error disliking post' });
69 | }
70 | });
71 |
72 | module.exports = router;
73 |
--------------------------------------------------------------------------------
/ai/recommendationEngine.js:
--------------------------------------------------------------------------------
1 | const { createClient } = require('redis');
2 | const axios = require('axios');
3 |
4 | class RecommendationEngine {
5 | constructor(redisUrl, apiUrl) {
6 | this.redisClient = createClient({ url: redisUrl });
7 | this.apiUrl = apiUrl;
8 | this.init();
9 | }
10 |
11 | // Initialize the Redis client
12 | async init() {
13 | await this.redisClient.connect();
14 | console.log('Connected to Redis');
15 | }
16 |
17 | // Function to get user preferences from Redis
18 | async getUser Preferences(userId) {
19 | const preferences = await this.redisClient.hGetAll(`user:${userId}:preferences`);
20 | return preferences;
21 | }
22 |
23 | // Function to fetch items from the API
24 | async fetchItems() {
25 | try {
26 | const response = await axios.get(this.apiUrl);
27 | return response.data.items; // Assuming the API returns an array of items
28 | } catch (error) {
29 | console.error('Error fetching items:', error.message);
30 | return [];
31 | }
32 | }
33 |
34 | // Function to generate recommendations based on user preferences
35 | async generateRecommendations(userId) {
36 | const preferences = await this.getUser Preferences(userId);
37 | const items = await this.fetchItems();
38 |
39 | // Simple recommendation logic based on preferences
40 | const recommendations = items.filter(item => {
41 | return preferences.categories.includes(item.category);
42 | });
43 |
44 | return recommendations;
45 | }
46 |
47 | // Function to save user preferences
48 | async saveUser Preferences(userId, preferences) {
49 | await this.redisClient.hSet(`user:${userId}:preferences`, preferences);
50 | console.log(`Preferences saved for user ${userId}`);
51 | }
52 |
53 | // Function to close the Redis connection
54 | async close() {
55 | await this.redisClient.quit();
56 | console.log('Disconnected from Redis');
57 | }
58 | }
59 |
60 | // Example usage
61 | const redisUrl = 'redis://localhost:6379';
62 | const apiUrl = 'https://api.example.com/items';
63 | const recommendationEngine = new RecommendationEngine(redisUrl, apiUrl);
64 |
65 | // Generate recommendations for a user
66 | const userId = 'user123';
67 | recommendationEngine.generateRecommendations(userId)
68 | .then(recommendations => {
69 | console.log('Recommendations:', recommendations);
70 | })
71 | .catch(error => {
72 | console.error('Error generating recommendations:', error);
73 | });
74 |
75 | // Export the RecommendationEngine class
76 | module.exports = RecommendationEngine;
77 |
--------------------------------------------------------------------------------
/src/backend/routes/aiRoutes.js:
--------------------------------------------------------------------------------
1 | // aiRoutes.js
2 |
3 | const express = require('express');
4 | const router = express.Router();
5 | const AIController = require('../controllers/aiController');
6 | const { authMiddleware } = require('../middleware/authMiddleware');
7 | const { validateRecommendationInput, validateFeedbackInput } = require('../middleware/inputValidationMiddleware');
8 |
9 | // Route to get personalized recommendations for a user
10 | router.get('/recommendations', authMiddleware, async (req, res) => {
11 | try {
12 | await AIController.getPersonalizedRecommendations(req, res);
13 | } catch (error) {
14 | res.status(500).json({ success: false, message: 'Error fetching recommendations' });
15 | }
16 | });
17 |
18 | // Route to analyze user feedback for sentiment
19 | router.post('/feedback/analyze', authMiddleware, validateFeedbackInput, async (req, res) => {
20 | try {
21 | await AIController.analyzeUser Feedback(req, res);
22 | } catch (error) {
23 | res.status(500).json({ success: false, message: 'Error analyzing feedback' });
24 | }
25 | });
26 |
27 | // Route to get user behavior analysis
28 | router.get('/behavior/analysis', authMiddleware, async (req, res) => {
29 | try {
30 | await AIController.getUser BehaviorAnalysis(req, res);
31 | } catch (error) {
32 | res.status(500).json({ success: false, message: 'Error fetching user behavior analysis' });
33 | }
34 | });
35 |
36 | // Route to get community engagement analysis
37 | router.get('/community/engagement/:communityId', authMiddleware, async (req, res) => {
38 | try {
39 | await AIController.getCommunityEngagementAnalysis(req, res);
40 | } catch (error) {
41 | res.status(500).json({ success: false, message: 'Error fetching community engagement analysis' });
42 | }
43 | });
44 |
45 | // Route to get AI-driven insights
46 | router.get('/insights', authMiddleware, async (req, res) => {
47 | try {
48 | const insights = await AIController.getAIInsights(req.user.id); // Assuming user ID is available
49 | res.status(200).json({ success: true, insights });
50 | } catch (error) {
51 | res.status(500).json({ success: false, message: 'Error fetching AI insights' });
52 | }
53 | });
54 |
55 | // Route to update user preferences for recommendations
56 | router.put('/preferences', authMiddleware, validateRecommendationInput, async (req, res) => {
57 | try {
58 | const updatedPreferences = await AIController.updateUser Preferences(req.user.id, req.body);
59 | res.status(200).json({ success: true, updatedPreferences });
60 | } catch (error) {
61 | res.status(500).json({ success: false, message: 'Error updating preferences' });
62 | }
63 | });
64 |
65 | module.exports = router;
66 |
--------------------------------------------------------------------------------
/src/frontend/js/payment.js:
--------------------------------------------------------------------------------
1 | // src/frontend/js/payment.js
2 |
3 | // Function to initiate a payment
4 | const initiatePayment = async (charityId, amount) => {
5 | try {
6 | const response = await fetch(`/api/charities/${charityId}/donate`, {
7 | method: 'POST',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | },
11 | body: JSON.stringify({ amount }),
12 | });
13 |
14 | if (!response.ok) {
15 | throw new Error('Payment initiation failed');
16 | }
17 |
18 | const result = await response.json();
19 | return result; // Return the payment result
20 | } catch (error) {
21 | console.error('Error initiating payment:', error);
22 | throw new Error('Failed to initiate payment. Please try again later.');
23 | }
24 | };
25 |
26 | // Function to handle payment confirmation
27 | const confirmPayment = async (paymentId) => {
28 | try {
29 | const response = await fetch(`/api/payments/${paymentId}/confirm`, {
30 | method: 'POST',
31 | headers: {
32 | 'Content-Type': 'application/json',
33 | },
34 | });
35 |
36 | if (!response.ok) {
37 | throw new Error('Payment confirmation failed');
38 | }
39 |
40 | const result = await response.json();
41 | return result; // Return the confirmation result
42 | } catch (error) {
43 | console.error('Error confirming payment:', error);
44 | throw new Error('Failed to confirm payment. Please try again later.');
45 | }
46 | };
47 |
48 | // Function to handle payment cancellation
49 | const cancelPayment = async (paymentId) => {
50 | try {
51 | const response = await fetch(`/api/payments/${paymentId}/cancel`, {
52 | method: 'POST',
53 | headers: {
54 | 'Content-Type': 'application/json',
55 | },
56 | });
57 |
58 | if (!response.ok) {
59 | throw new Error('Payment cancellation failed');
60 | }
61 |
62 | const result = await response.json();
63 | return result; // Return the cancellation result
64 | } catch (error) {
65 | console.error('Error cancelling payment:', error);
66 | throw new Error('Failed to cancel payment. Please try again later.');
67 | }
68 | };
69 |
70 | // Function to validate payment information
71 | const validatePaymentInfo = (amount) => {
72 | if (!amount || isNaN(amount) || amount <= 0) {
73 | throw new Error('Invalid payment amount. Please enter a positive number.');
74 | }
75 | };
76 |
77 | // Exporting the payment functions
78 | export {
79 | initiatePayment,
80 | confirmPayment,
81 | cancelPayment,
82 | validatePaymentInfo,
83 | };
84 |
--------------------------------------------------------------------------------
/src/frontend/css/animations.css:
--------------------------------------------------------------------------------
1 | /* Base transition styles */
2 | * {
3 | box-sizing: border-box;
4 | }
5 |
6 | body {
7 | transition: background-color 0.3s ease, color 0.3s ease;
8 | }
9 |
10 | /* Fade In Animation */
11 | .fade-in {
12 | animation: fadeIn 0.5s ease-in forwards;
13 | }
14 |
15 | @keyframes fadeIn {
16 | from {
17 | opacity: 0;
18 | }
19 | to {
20 | opacity: 1;
21 | }
22 | }
23 |
24 | /* Fade Out Animation */
25 | .fade-out {
26 | animation: fadeOut 0.5s ease-out forwards;
27 | }
28 |
29 | @keyframes fadeOut {
30 | from {
31 | opacity: 1;
32 | }
33 | to {
34 | opacity: 0;
35 | }
36 | }
37 |
38 | /* Slide In Animation */
39 | .slide-in {
40 | animation: slideIn 0.5s ease-in forwards;
41 | }
42 |
43 | @keyframes slideIn {
44 | from {
45 | transform: translateX(-100%);
46 | opacity: 0;
47 | }
48 | to {
49 | transform: translateX(0);
50 | opacity: 1;
51 | }
52 | }
53 |
54 | /* Slide Out Animation */
55 | .slide-out {
56 | animation: slideOut 0.5s ease-out forwards;
57 | }
58 |
59 | @keyframes slideOut {
60 | from {
61 | transform: translateX(0);
62 | opacity: 1;
63 | }
64 | to {
65 | transform: translateX(-100%);
66 | opacity: 0;
67 | }
68 | }
69 |
70 | /* Bounce Animation */
71 | .bounce {
72 | animation: bounce 0.6s infinite;
73 | }
74 |
75 | @keyframes bounce {
76 | 0%, 20%, 50%, 80%, 100% {
77 | transform: translateY(0);
78 | }
79 | 40% {
80 | transform: translateY(-30px);
81 | }
82 | 60% {
83 | transform: translateY(-15px);
84 | }
85 | }
86 |
87 | /* Scale Up Animation */
88 | .scale-up {
89 | animation: scaleUp 0.3s ease-in forwards;
90 | }
91 |
92 | @keyframes scaleUp {
93 | from {
94 | transform: scale(0);
95 | }
96 | to {
97 | transform: scale(1);
98 | }
99 | }
100 |
101 | /* Scale Down Animation */
102 | .scale-down {
103 | animation: scaleDown 0.3s ease-out forwards;
104 | }
105 |
106 | @keyframes scaleDown {
107 | from {
108 | transform: scale(1);
109 | }
110 | to {
111 | transform: scale(0);
112 | }
113 | }
114 |
115 | /* Rotate Animation */
116 | .rotate {
117 | animation: rotate 0.5s ease-in-out forwards;
118 | }
119 |
120 | @keyframes rotate {
121 | from {
122 | transform: rotate(0deg);
123 | }
124 | to {
125 | transform: rotate(360deg);
126 | }
127 | }
128 |
129 | /* Utility Classes for Transitions */
130 | .transition {
131 | transition: all 0.3s ease;
132 | }
133 |
134 | .transition-fast {
135 | transition: all 0.2s ease;
136 | }
137 |
138 | .transition-slow {
139 | transition: all 0.5s ease;
140 | }
141 |
--------------------------------------------------------------------------------
/src/frontend/js/app.js:
--------------------------------------------------------------------------------
1 | // src/frontend/js/app.js
2 |
3 | // Function to fetch charities from the API
4 | const fetchCharities = async () => {
5 | try {
6 | const response = await fetch('/api/charities');
7 | if (!response.ok) {
8 | throw new Error('Network response was not ok');
9 | }
10 | const charities = await response.json();
11 | renderCharities(charities);
12 | } catch (error) {
13 | console.error('Error fetching charities:', error);
14 | displayError('Failed to load charities. Please try again later.');
15 | }
16 | };
17 |
18 | // Function to render charity cards
19 | const renderCharities = (charities) => {
20 | const charityList = document.getElementById('charity-list');
21 | charityList.innerHTML = ''; // Clear existing content
22 |
23 | charities.forEach(charity => {
24 | const charityCard = document.createElement('div');
25 | charityCard.className = 'col-md-4 charity-card';
26 | charityCard.innerHTML = `
27 | ${charity.name}
28 | ${charity.description}
29 |
30 | `;
31 | charityList.appendChild(charityCard);
32 | });
33 | };
34 |
35 | // Function to handle donations
36 | const donate = async (charityId) => {
37 | const amount = prompt('Enter donation amount:');
38 | if (amount && !isNaN(amount) && amount > 0) {
39 | try {
40 | const response = await fetch(`/api/charities/${charityId}/donate`, {
41 | method: 'POST',
42 | headers: {
43 | 'Content-Type': 'application/json',
44 | },
45 | body: JSON.stringify({ amount }),
46 | });
47 | if (!response.ok) {
48 | throw new Error('Network response was not ok');
49 | }
50 | const result = await response.json();
51 | alert(`Thank you for your donation of $${amount} to ${result.charityName}!`);
52 | } catch (error) {
53 | console.error('Error processing donation:', error);
54 | displayError('Failed to process donation. Please try again later.');
55 | }
56 | } else {
57 | alert('Please enter a valid donation amount.');
58 | }
59 | };
60 |
61 | // Function to display error messages
62 | const displayError = (message) => {
63 | const charityList = document.getElementById('charity-list');
64 | charityList.innerHTML = `${message}
`;
65 | };
66 |
67 | // Initialize the application
68 | const init = () => {
69 | fetchCharities(); // Fetch and display charities on page load
70 | };
71 |
72 | // Run the initialization function when the DOM is fully loaded
73 | document.addEventListener('DOMContentLoaded', init);
74 |
--------------------------------------------------------------------------------
/src/backend/controllers/fraudDetectionController.js:
--------------------------------------------------------------------------------
1 | // fraudDetectionController.js
2 |
3 | const FraudDetectionService = require('../services/fraudService');
4 | const UserService = require('../services/userService');
5 | const { validateFraudReport } = require('../middleware/inputValidationMiddleware');
6 |
7 | // Fraud Detection Controller for handling fraudulent activities
8 |
9 | class FraudDetectionController {
10 | // Report potential fraud
11 | async reportFraud(req, res) {
12 | try {
13 | const { userId, transactionId, reason } = req.body;
14 | validateFraudReport(req.body); // Validate input
15 |
16 | // Log the fraud report
17 | const report = await FraudDetectionService.logFraudReport(userId, transactionId, reason);
18 | return res.status(201).json({ success: true, report });
19 | } catch (error) {
20 | console.error('Error reporting fraud:', error);
21 | return res.status(500).json({ success: false, message: 'Internal Server Error' });
22 | }
23 | }
24 |
25 | // Analyze transactions for potential fraud
26 | async analyzeTransactions(req, res) {
27 | try {
28 | const transactions = await FraudDetectionService.getRecentTransactions();
29 | const fraudAlerts = await FraudDetectionService.detectFraud(transactions);
30 | return res.status(200).json({ success: true, fraudAlerts });
31 | } catch (error) {
32 | console.error('Error analyzing transactions:', error);
33 | return res.status(500).json({ success: false, message: 'Internal Server Error' });
34 | }
35 | }
36 |
37 | // Get fraud reports for a user
38 | async getUser FraudReports(req, res) {
39 | try {
40 | const userId = req.user.id; // Assuming user ID is available in the request
41 | const reports = await FraudDetectionService.getFraudReportsByUser (userId);
42 | return res.status(200).json({ success: true, reports });
43 | } catch (error) {
44 | console.error('Error fetching user fraud reports:', error);
45 | return res.status(500).json({ success: false, message: 'Internal Server Error' });
46 | }
47 | }
48 |
49 | // Review and take action on fraud alerts
50 | async reviewFraudAlert(req, res) {
51 | try {
52 | const { alertId, action } = req.body; // Action could be 'investigate', 'dismiss', etc.
53 | const result = await FraudDetectionService.takeActionOnFraudAlert(alertId, action);
54 | return res.status(200).json({ success: true, result });
55 | } catch (error) {
56 | console.error('Error reviewing fraud alert:', error);
57 | return res.status(500).json({ success: false, message: 'Internal Server Error' });
58 | }
59 | }
60 | }
61 |
62 | module.exports = new FraudDetectionController();
63 |
--------------------------------------------------------------------------------
/src/backend/services/eventService.js:
--------------------------------------------------------------------------------
1 | // eventService.js
2 |
3 | const EventModel = require('../models/eventModel'); // Assuming eventModel contains the Event schema
4 | const RegistrationModel = require('../models/registrationModel'); // Assuming a separate Registration model exists
5 | const UserModel = require('../models/userModel'); // Assuming a User model exists
6 |
7 | class EventService {
8 | // Create a new event
9 | async createEvent(userId, title, description, date, location, capacity) {
10 | const newEvent = new EventModel({
11 | userId,
12 | title,
13 | description,
14 | date,
15 | location,
16 | capacity,
17 | });
18 | await newEvent.save();
19 | return newEvent;
20 | }
21 |
22 | // Get all events
23 | async getAllEvents() {
24 | return await EventModel.find()
25 | .populate('userId', 'username') // Populate user details
26 | .sort({ date: 1 }); // Sort by event date
27 | }
28 |
29 | // Get a single event by ID
30 | async getEventById(eventId) {
31 | const event = await EventModel.findById(eventId).populate('userId', 'username');
32 | if (!event) {
33 | throw new Error('Event not found');
34 | }
35 | return event;
36 | }
37 |
38 | // Register for an event
39 | async registerForEvent(userId, eventId) {
40 | const event = await EventModel.findById(eventId);
41 | if (!event) {
42 | throw new Error('Event not found');
43 | }
44 | if (event.capacity <= 0) {
45 | throw new Error('Event is fully booked');
46 | }
47 |
48 | const registration = new RegistrationModel({
49 | userId,
50 | eventId,
51 | });
52 | await registration.save();
53 |
54 | // Decrease the event capacity
55 | event.capacity -= 1;
56 | await event.save();
57 |
58 | return registration;
59 | }
60 |
61 | // Get registrations for a specific event
62 | async getEventRegistrations(eventId) {
63 | return await RegistrationModel.find({ eventId })
64 | .populate('userId', 'username') // Populate user details
65 | .sort({ createdAt: -1 }); // Sort by registration date
66 | }
67 |
68 | // Cancel registration for an event
69 | async cancelRegistration(userId, eventId) {
70 | const registration = await RegistrationModel.findOneAndDelete({ userId, eventId });
71 | if (!registration) {
72 | throw new Error('Registration not found');
73 | }
74 |
75 | // Increase the event capacity
76 | const event = await EventModel.findById(eventId);
77 | event.capacity += 1;
78 | await event.save();
79 |
80 | return { message: 'Registration canceled successfully' };
81 | }
82 | }
83 |
84 | module.exports = new EventService();
85 |
--------------------------------------------------------------------------------
/src/backend/services/communityService.js:
--------------------------------------------------------------------------------
1 | // communityService.js
2 |
3 | const PostModel = require('../models/communityModel'); // Assuming communityModel contains the Post schema
4 | const CommentModel = require('../models/commentModel'); // Assuming a separate Comment model exists
5 | const UserModel = require('../models/userModel'); // Assuming a User model exists
6 |
7 | class CommunityService {
8 | // Create a new post
9 | async createPost(userId, title, content) {
10 | const newPost = new PostModel({
11 | userId,
12 | title,
13 | content,
14 | });
15 | await newPost.save();
16 | return newPost;
17 | }
18 |
19 | // Get all posts
20 | async getAllPosts() {
21 | return await PostModel.find()
22 | .populate('userId', 'username') // Populate user details
23 | .sort({ createdAt: -1 }); // Sort by creation date
24 | }
25 |
26 | // Get a single post by ID
27 | async getPostById(postId) {
28 | const post = await PostModel.findById(postId).populate('userId', 'username');
29 | if (!post) {
30 | throw new Error('Post not found');
31 | }
32 | return post;
33 | }
34 |
35 | // Create a comment on a post
36 | async createComment(userId, postId, content) {
37 | const newComment = new CommentModel({
38 | userId,
39 | postId,
40 | content,
41 | });
42 | await newComment.save();
43 | return newComment;
44 | }
45 |
46 | // Get comments for a specific post
47 | async getCommentsForPost(postId) {
48 | return await CommentModel.find({ postId })
49 | .populate('userId', 'username') // Populate user details
50 | .sort({ createdAt: -1 }); // Sort by creation date
51 | }
52 |
53 | // Like a post
54 | async likePost(userId, postId) {
55 | const post = await PostModel.findById(postId);
56 | if (!post) {
57 | throw new Error('Post not found');
58 | }
59 | if (!post.likes.includes(userId)) {
60 | post.likes.push(userId); // Add user ID to likes
61 | await post.save();
62 | return { message: 'Post liked successfully' };
63 | }
64 | return { message: 'Post already liked' };
65 | }
66 |
67 | // Dislike a post
68 | async dislikePost(userId, postId) {
69 | const post = await PostModel.findById(postId);
70 | if (!post) {
71 | throw new Error('Post not found');
72 | }
73 | if (post.likes.includes(userId)) {
74 | post.likes = post.likes.filter(id => id.toString() !== userId.toString()); // Remove user ID from likes
75 | await post.save();
76 | return { message: 'Post disliked successfully' };
77 | }
78 | return { message: 'Post not liked yet' };
79 | }
80 | }
81 |
82 | module.exports = new CommunityService();
83 |
--------------------------------------------------------------------------------
/src/frontend/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | PiConnect Ecosystem - The Future of Charitable Giving
7 |
8 |
9 |
10 |
11 |
31 |
32 |
33 |
34 | Welcome to PiConnect Ecosystem
35 | Empowering Charitable Giving with Technology
36 | Explore Charities
37 |
38 |
39 |
40 |
41 |
Explore Charities
42 |
43 |
44 |
45 |
46 |
47 |
48 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/src/backend/controllers/notificationController.js:
--------------------------------------------------------------------------------
1 | // src/backend/controllers/notificationController.js
2 | const Notification = require('../models/notificationModel');
3 |
4 | // Send a notification
5 | exports.sendNotification = async (req, res) => {
6 | const { userId, message } = req.body;
7 |
8 | // Validate input
9 | if (!userId || !message) {
10 | return res.status(400).send({ message: 'User ID and message are required.' });
11 | }
12 |
13 | try {
14 | // Create a new notification
15 | const newNotification = new Notification({ userId, message });
16 | await newNotification.save();
17 |
18 | // Respond with success
19 | res.status(201).send({ message: 'Notification sent successfully', notification: newNotification });
20 | } catch (error) {
21 | console.error('Error sending notification:', error);
22 | res.status(500).send({ message: 'Failed to send notification', error });
23 | }
24 | };
25 |
26 | // Get notifications for a specific user
27 | exports.getUser Notifications = async (req, res) => {
28 | const { userId } = req.params;
29 |
30 | try {
31 | // Retrieve notifications for the user
32 | const notifications = await Notification.find({ userId }).sort({ createdAt: -1 }); // Sort by most recent
33 | res.status(200).send(notifications);
34 | } catch (error) {
35 | console.error('Error retrieving user notifications:', error);
36 | res.status(500).send({ message: 'Failed to retrieve notifications', error });
37 | }
38 | };
39 |
40 | // Mark a notification as read
41 | exports.markNotificationAsRead = async (req, res) => {
42 | const { notificationId } = req.params;
43 |
44 | try {
45 | const updatedNotification = await Notification.findByIdAndUpdate(
46 | notificationId,
47 | { isRead: true },
48 | { new: true }
49 | );
50 |
51 | if (!updatedNotification) {
52 | return res.status(404).send({ message: 'Notification not found' });
53 | }
54 |
55 | res.status(200).send({ message: 'Notification marked as read', notification: updatedNotification });
56 | } catch (error) {
57 | console.error('Error marking notification as read:', error);
58 | res.status(500).send({ message: 'Failed to mark notification as read', error });
59 | }
60 | };
61 |
62 | // Delete a notification
63 | exports.deleteNotification = async (req, res) => {
64 | const { notificationId } = req.params;
65 |
66 | try {
67 | const deletedNotification = await Notification.findByIdAndDelete(notificationId);
68 | if (!deletedNotification) {
69 | return res.status(404).send({ message: 'Notification not found' });
70 | }
71 | res.status(200).send({ message: 'Notification deleted successfully' });
72 | } catch (error) {
73 | console.error('Error deleting notification:', error);
74 | res.status(500).send({ message: 'Failed to delete notification', error });
75 | }
76 | };
77 |
--------------------------------------------------------------------------------
/src/backend/controllers/analyticsController.js:
--------------------------------------------------------------------------------
1 | // src/backend/controllers/analyticsController.js
2 | const Payment = require('../models/transactionModel');
3 | const User = require('../models/userModel');
4 | const Charity = require('../models/charityModel');
5 |
6 | // Get overall analytics data
7 | exports.getAnalyticsData = async (req, res) => {
8 | try {
9 | // Count total users
10 | const totalUsers = await User.countDocuments();
11 |
12 | // Count total payments
13 | const totalPayments = await Payment.countDocuments();
14 |
15 | // Calculate total amount of payments
16 | const totalPaymentAmount = await Payment.aggregate([
17 | { $group: { _id: null, totalAmount: { $sum: '$amount' } } }
18 | ]);
19 |
20 | // Count total charities
21 | const totalCharities = await Charity.countDocuments();
22 |
23 | // Prepare analytics data
24 | const analyticsData = {
25 | totalUsers,
26 | totalPayments,
27 | totalPaymentAmount: totalPaymentAmount[0] ? totalPaymentAmount[0].totalAmount : 0,
28 | totalCharities
29 | };
30 |
31 | // Respond with analytics data
32 | res.status(200).send(analyticsData);
33 | } catch (error) {
34 | console.error('Error retrieving analytics data:', error);
35 | res.status(500).send({ message: 'Failed to retrieve analytics data', error });
36 | }
37 | };
38 |
39 | // Get payment analytics for a specific user
40 | exports.getUser PaymentAnalytics = async (req, res) => {
41 | const { userId } = req.params;
42 |
43 | try {
44 | // Retrieve payment history for the user
45 | const payments = await Payment.find({ userId });
46 |
47 | // Calculate total payments and total amount
48 | const totalPayments = payments.length;
49 | const totalPaymentAmount = payments.reduce((acc, payment) => acc + payment.amount, 0);
50 |
51 | // Prepare user payment analytics data
52 | const userPaymentAnalytics = {
53 | userId,
54 | totalPayments,
55 | totalPaymentAmount
56 | };
57 |
58 | // Respond with user payment analytics data
59 | res.status(200).send(userPaymentAnalytics);
60 | } catch (error) {
61 | console.error('Error retrieving user payment analytics:', error);
62 | res.status(500).send({ message: 'Failed to retrieve user payment analytics', error });
63 | }
64 | };
65 |
66 | // Get charity analytics
67 | exports.getCharityAnalytics = async (req, res) => {
68 | try {
69 | // Count total charities
70 | const totalCharities = await Charity.countDocuments();
71 |
72 | // Prepare charity analytics data
73 | const charityAnalytics = {
74 | totalCharities
75 | };
76 |
77 | // Respond with charity analytics data
78 | res.status(200).send(charityAnalytics);
79 | } catch (error) {
80 | console.error('Error retrieving charity analytics:', error);
81 | res.status(500).send({ message: 'Failed to retrieve charity analytics', error });
82 | }
83 | };
84 |
--------------------------------------------------------------------------------
/ai/trainingData/communityData.json:
--------------------------------------------------------------------------------
1 | {
2 | "members": [
3 | {
4 | "memberId": "member1",
5 | "name": "Alice",
6 | "joinDate": "2023-01-15",
7 | "isActive": true,
8 | "contributions": 10,
9 | "eventsParticipated": ["event1", "event2"]
10 | },
11 | {
12 | "memberId": "member2",
13 | "name": "Bob",
14 | "joinDate": "2023-02-20",
15 | "isActive": true,
16 | "contributions": 5,
17 | "eventsParticipated": ["event1"]
18 | },
19 | {
20 | "memberId": "member3",
21 | "name": "Charlie",
22 | "joinDate": "2023-03-10",
23 | "isActive": false,
24 | "contributions": 0,
25 | "eventsParticipated": []
26 | },
27 | {
28 | "memberId": "member4",
29 | "name": "David",
30 | "joinDate": "2023-04-05",
31 | "isActive": true,
32 | "contributions": 8,
33 | "eventsParticipated": ["event2", "event3"]
34 | }
35 | ],
36 | "events": [
37 | {
38 | "eventId": "event1",
39 | "title": "Community Meetup",
40 | "description": "A gathering for community members to discuss ideas and projects.",
41 | "date": "2023-10-01",
42 | "participants": ["member1", "member2"]
43 | },
44 | {
45 | "eventId": "event2",
46 | "title": "Online Workshop",
47 | "description": "An interactive workshop on community building.",
48 | "date": "2023-10-15",
49 | "participants": ["member1", "member4"]
50 | },
51 | {
52 | "eventId": "event3",
53 | "title": "Charity Event",
54 | "description": "A charity event to raise funds for local causes.",
55 | "date": "2023-10-20",
56 | "participants": ["member4"]
57 | }
58 | ],
59 | "interactions": [
60 | {
61 | "interactionId": "interaction1",
62 | "memberId": "member1",
63 | "eventId": "event1",
64 | "action": "comment",
65 | "content": "Excited for this meetup!",
66 | "timestamp": "2023-09-25T10:00:00Z"
67 | },
68 | {
69 | "interactionId": "interaction2",
70 | "memberId": "member2",
71 | "eventId": "event1",
72 | "action": "like",
73 | "content": null,
74 | "timestamp": "2023-09-26T11:15:00Z"
75 | },
76 | {
77 | "interactionId": "interaction3",
78 | "memberId": "member4",
79 | "eventId": "event2",
80 | "action": "register",
81 | "content": null,
82 | "timestamp": "2023-09-27T09:30:00Z"
83 | },
84 | {
85 | "interactionId": "interaction4",
86 | "memberId": "member1",
87 | "eventId": "event3",
88 | "action": "share",
89 | "content": "Looking forward to the charity event!",
90 | "timestamp": "2023-09-28T14:00:00Z"
91 | }
92 | ]
93 | }
94 |
--------------------------------------------------------------------------------
/ai/userBehaviorAnalysis.js:
--------------------------------------------------------------------------------
1 | // userBehaviorAnalysis.js
2 |
3 | // Sample data structure for user interactions
4 | const userInteractions = [
5 | { userId: 'user1', actions: ['login', 'view', 'comment', 'like'], timestamp: '2023-10-01T10:00:00Z' },
6 | { userId: 'user2', actions: ['login', 'view', 'like'], timestamp: '2023-10-01T11:00:00Z' },
7 | { userId: 'user1', actions: ['login', 'view', 'share'], timestamp: '2023-10-02T09:00:00Z' },
8 | { userId: 'user3', actions: ['login', 'comment'], timestamp: '2023-10-02T10:30:00Z' },
9 | { userId: 'user2', actions: ['login', 'view', 'comment'], timestamp: '2023-10-03T12:00:00Z' },
10 | ];
11 |
12 | /**
13 | * Calculate the total number of unique users.
14 | * @returns {number} The count of unique users.
15 | */
16 | function getUniqueUser Count() {
17 | const uniqueUsers = new Set(userInteractions.map(interaction => interaction.userId));
18 | return uniqueUsers.size;
19 | }
20 |
21 | /**
22 | * Calculate the total number of actions performed by users.
23 | * @returns {number} The total number of actions.
24 | */
25 | function getTotalActions() {
26 | return userInteractions.reduce((total, interaction) => total + interaction.actions.length, 0);
27 | }
28 |
29 | /**
30 | * Get the most common actions performed by users.
31 | * @returns {Object} An object containing action counts.
32 | */
33 | function getMostCommonActions() {
34 | const actionCounts = {};
35 |
36 | userInteractions.forEach(interaction => {
37 | interaction.actions.forEach(action => {
38 | actionCounts[action] = (actionCounts[action] || 0) + 1;
39 | });
40 | });
41 |
42 | return actionCounts;
43 | }
44 |
45 | /**
46 | * Get user engagement metrics over a specified time period.
47 | * @param {string} startDate - The start date in ISO format.
48 | * @param {string} endDate - The end date in ISO format.
49 | * @returns {Object} An object containing engagement metrics.
50 | */
51 | function getEngagementMetrics(startDate, endDate) {
52 | const filteredInteractions = userInteractions.filter(interaction => {
53 | const timestamp = new Date(interaction.timestamp);
54 | return timestamp >= new Date(startDate) && timestamp <= new Date(endDate);
55 | });
56 |
57 | const uniqueUsers = new Set(filteredInteractions.map(interaction => interaction.userId));
58 | const totalActions = filteredInteractions.reduce((total, interaction) => total + interaction.actions.length, 0);
59 |
60 | return {
61 | uniqueUser Count: uniqueUsers.size,
62 | totalActions,
63 | };
64 | }
65 |
66 | // Example usage
67 | const uniqueUser Count = getUniqueUser Count();
68 | const totalActions = getTotalActions();
69 | const mostCommonActions = getMostCommonActions();
70 | const engagementMetrics = getEngagementMetrics('2023-10-01', '2023-10-02');
71 |
72 | console.log('Unique User Count:', uniqueUser Count);
73 | console.log('Total Actions:', totalActions);
74 | console.log('Most Common Actions:', mostCommonActions);
75 | console.log('Engagement Metrics:', engagementMetrics);
76 |
77 | module.exports = {
78 | getUniqueUser Count,
79 | getTotalActions,
80 | getMostCommonActions,
81 | getEngagementMetrics,
82 | };
83 |
--------------------------------------------------------------------------------
/src/backend/controllers/userController.js:
--------------------------------------------------------------------------------
1 | // src/backend/controllers/userController.js
2 | const User = require('../models/userModel');
3 | const bcrypt = require('bcrypt');
4 | const jwt = require('jsonwebtoken');
5 |
6 | // Register a new user
7 | exports.registerUser = async (req, res) => {
8 | const { username, password } = req.body;
9 |
10 | // Validate input
11 | if (!username || !password) {
12 | return res.status(400).send({ message: 'Username and password are required.' });
13 | }
14 |
15 | try {
16 | // Check if the user already exists
17 | const existingUser = await User.findOne({ username });
18 | if (existingUser ) {
19 | return res.status(400).send({ message: 'Username already taken.' });
20 | }
21 |
22 | // Hash the password
23 | const hashedPassword = await bcrypt.hash(password, 10);
24 |
25 | // Create a new user
26 | const newUser = new User({ username, password: hashedPassword });
27 | await newUser .save();
28 |
29 | // Respond with success
30 | res.status(201).send({ message: 'User registered successfully', user: newUser });
31 | } catch (error) {
32 | console.error('User registration error:', error);
33 | res.status(500).send({ message: 'User registration failed', error });
34 | }
35 | };
36 |
37 | // Login a user
38 | exports.loginUser = async (req, res) => {
39 | const { username, password } = req.body;
40 |
41 | // Validate input
42 | if (!username || !password) {
43 | return res.status(400).send({ message: 'Username and password are required.' });
44 | }
45 |
46 | try {
47 | // Find the user by username
48 | const user = await User.findOne({ username });
49 | if (!user) {
50 | return res.status(401).send({ message: 'Invalid credentials' });
51 | }
52 |
53 | // Compare the password with the hashed password
54 | const isMatch = await bcrypt.compare(password, user.password);
55 | if (!isMatch) {
56 | return res.status(401).send({ message: 'Invalid credentials' });
57 | }
58 |
59 | // Generate a JWT token
60 | const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET, { expiresIn: '1h' });
61 |
62 | // Respond with success
63 | res.status(200).send({ message: 'Login successful', token });
64 | } catch (error) {
65 | console.error('User login error:', error);
66 | res.status(500).send({ message: 'Login failed', error });
67 | }
68 | };
69 |
70 | // Get user information
71 | exports.getUser Info = async (req, res) => {
72 | const { userId } = req.params;
73 |
74 | try {
75 | // Find the user by ID
76 | const user = await User.findById(userId).select('-password'); // Exclude password from response
77 | if (!user) {
78 | return res.status(404).send({ message: 'User not found' });
79 | }
80 |
81 | // Respond with user information
82 | res.status(200).send(user);
83 | } catch (error) {
84 | console.error('Error retrieving user information:', error);
85 | res.status(500).send({ message: 'Failed to retrieve user information', error });
86 | }
87 | };
88 |
--------------------------------------------------------------------------------
/src/backend/controllers/aiController.js:
--------------------------------------------------------------------------------
1 | // aiController.js
2 |
3 | const UserService = require('../services/userService');
4 | const RecommendationService = require('../services/aiService');
5 | const SentimentAnalysisService = require('../services/sentimentAnalysisService');
6 | const { validateUser Input } = require('../middleware/inputValidationMiddleware');
7 |
8 | // AI Controller for handling AI-driven features and recommendations
9 |
10 | class AIController {
11 | // Get personalized recommendations for a user
12 | async getPersonalizedRecommendations(req, res) {
13 | try {
14 | const userId = req.user.id; // Assuming user ID is available in the request
15 | const userPreferences = await UserService.getUser Preferences(userId);
16 | const recommendations = await RecommendationService.generateRecommendations(userPreferences);
17 | return res.status(200).json({ success: true, recommendations });
18 | } catch (error) {
19 | console.error('Error fetching recommendations:', error);
20 | return res.status(500).json({ success: false, message: 'Internal Server Error' });
21 | }
22 | }
23 |
24 | // Analyze user feedback for sentiment
25 | async analyzeUser Feedback(req, res) {
26 | try {
27 | const { feedback } = req.body;
28 | validateUser Input(feedback); // Validate input
29 | const sentimentScore = await SentimentAnalysisService.analyzeSentiment(feedback);
30 | return res.status(200).json({ success: true, sentimentScore });
31 | } catch (error) {
32 | console.error('Error analyzing feedback:', error);
33 | return res.status(500).json({ success: false, message: 'Internal Server Error' });
34 | }
35 | }
36 |
37 | // Get user behavior analysis
38 | async getUser BehaviorAnalysis(req, res) {
39 | try {
40 | const userId = req.user.id; // Assuming user ID is available in the request
41 | const behaviorData = await UserService.getUser BehaviorData(userId);
42 | const analysisResults = await RecommendationService.analyzeUser Behavior(behaviorData);
43 | return res.status(200).json({ success: true, analysisResults });
44 | } catch (error) {
45 | console.error('Error fetching user behavior analysis:', error);
46 | return res.status(500).json({ success: false, message: 'Internal Server Error' });
47 | }
48 | }
49 |
50 | // Get community engagement analysis
51 | async getCommunityEngagementAnalysis(req, res) {
52 | try {
53 | const communityId = req.params.communityId; // Get community ID from request parameters
54 | const engagementData = await UserService.getCommunityEngagementData(communityId);
55 | const analysisResults = await RecommendationService.analyzeCommunityEngagement(engagementData);
56 | return res.status(200).json({ success: true, analysisResults });
57 | } catch (error) {
58 | console.error('Error fetching community engagement analysis:', error);
59 | return res.status(500).json({ success: false, message: 'Internal Server Error' });
60 | }
61 | }
62 | }
63 |
64 | module.exports = new AIController();
65 |
--------------------------------------------------------------------------------
/src/backend/controllers/charityController.js:
--------------------------------------------------------------------------------
1 | // src/backend/controllers/charityController.js
2 | const Charity = require('../models/charityModel');
3 |
4 | // Create a new charity
5 | exports.createCharity = async (req, res) => {
6 | const { name, description } = req.body;
7 |
8 | // Validate input
9 | if (!name || !description) {
10 | return res.status(400).send({ message: 'Name and description are required.' });
11 | }
12 |
13 | try {
14 | // Create a new charity
15 | const newCharity = new Charity({ name, description });
16 | await newCharity.save();
17 |
18 | // Respond with success
19 | res.status(201).send({ message: 'Charity created successfully', charity: newCharity });
20 | } catch (error) {
21 | console.error('Charity creation error:', error);
22 | res.status(500).send({ message: 'Charity creation failed', error });
23 | }
24 | };
25 |
26 | // Get all charities
27 | exports.getAllCharities = async (req, res) => {
28 | try {
29 | const charities = await Charity.find();
30 | res.status(200).send(charities);
31 | } catch (error) {
32 | console.error('Error retrieving charities:', error);
33 | res.status(500).send({ message: 'Failed to retrieve charities', error });
34 | }
35 | };
36 |
37 | // Get a specific charity by ID
38 | exports.getCharityById = async (req, res) => {
39 | const { charityId } = req.params;
40 |
41 | try {
42 | const charity = await Charity.findById(charityId);
43 | if (!charity) {
44 | return res.status(404).send({ message: 'Charity not found' });
45 | }
46 | res.status(200).send(charity);
47 | } catch (error) {
48 | console.error('Error retrieving charity:', error);
49 | res.status(500).send({ message: 'Failed to retrieve charity', error });
50 | }
51 | };
52 |
53 | // Update a charity by ID
54 | exports.updateCharity = async (req, res) => {
55 | const { charityId } = req.params;
56 | const { name, description } = req.body;
57 |
58 | try {
59 | const updatedCharity = await Charity.findByIdAndUpdate(
60 | charityId,
61 | { name, description },
62 | { new: true, runValidators: true }
63 | );
64 |
65 | if (!updatedCharity) {
66 | return res.status(404).send({ message: 'Charity not found' });
67 | }
68 |
69 | res.status(200).send({ message: 'Charity updated successfully', charity: updatedCharity });
70 | } catch (error) {
71 | console.error('Charity update error:', error);
72 | res.status(500).send({ message: 'Charity update failed', error });
73 | }
74 | };
75 |
76 | // Delete a charity by ID
77 | exports.deleteCharity = async (req, res) => {
78 | const { charityId } = req.params;
79 |
80 | try {
81 | const deletedCharity = await Charity.findByIdAndDelete(charityId);
82 | if (!deletedCharity) {
83 | return res.status(404).send({ message: 'Charity not found' });
84 | }
85 | res.status(200).send({ message: 'Charity deleted successfully' });
86 | } catch (error) {
87 | console.error('Charity deletion error:', error);
88 | res.status(500).send({ message: 'Charity deletion failed', error });
89 | }
90 | };
91 |
--------------------------------------------------------------------------------
/src/frontend/components/NotificationBell.js:
--------------------------------------------------------------------------------
1 | // src/frontend/components/NotificationBell.js
2 |
3 | import React, { useEffect, useState } from 'react';
4 | import { fetchUser Notifications } from '../js/notification'; // Import the notification fetching function
5 | import PropTypes from 'prop-types';
6 |
7 | const NotificationBell = ({ userId }) => {
8 | const [notifications, setNotifications] = useState([]);
9 | const [unreadCount, setUnreadCount] = useState(0);
10 | const [loading, setLoading] = useState(true);
11 | const [error, setError] = useState(null);
12 | const [showDropdown, setShowDropdown] = useState(false);
13 |
14 | // Function to fetch notifications for the user
15 | const loadNotifications = async () => {
16 | try {
17 | const data = await fetchUser Notifications(userId);
18 | setNotifications(data);
19 | setUnreadCount(data.filter(notification => !notification.read).length);
20 | } catch (err) {
21 | setError(err.message);
22 | } finally {
23 | setLoading(false);
24 | }
25 | };
26 |
27 | useEffect(() => {
28 | loadNotifications();
29 | }, [userId]);
30 |
31 | const toggleDropdown = () => {
32 | setShowDropdown(!showDropdown);
33 | };
34 |
35 | const markAsRead = (notificationId) => {
36 | // Logic to mark notification as read (could be an API call)
37 | setNotifications(prevNotifications =>
38 | prevNotifications.map(notification =>
39 | notification.id === notificationId ? { ...notification, read: true } : notification
40 | )
41 | );
42 | setUnreadCount(prevCount => prevCount - 1);
43 | };
44 |
45 | if (loading) {
46 | return Loading notifications...
;
47 | }
48 |
49 | if (error) {
50 | return {error}
;
51 | }
52 |
53 | return (
54 |
55 |
59 | {showDropdown && (
60 |
61 |
Notifications
62 | {notifications.length > 0 ? (
63 | notifications.map(notification => (
64 |
markAsRead(notification.id)}>
65 |
66 | {notification.message}
67 |
68 |
69 | ))
70 | ) : (
71 |
No notifications
72 | )}
73 |
74 | )}
75 |
76 | );
77 | };
78 |
79 | NotificationBell.propTypes = {
80 | userId: PropTypes.string.isRequired,
81 | };
82 |
83 | export default NotificationBell;
84 |
--------------------------------------------------------------------------------
/blockchain/smartContracts/charityContract.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.0;
3 |
4 | import "@openzeppelin/contracts/access/Ownable.sol";
5 | import "@openzeppelin/contracts/utils/math/SafeMath.sol";
6 |
7 | contract CharityContract is Ownable {
8 | using SafeMath for uint256;
9 |
10 | // Struct to represent a charity
11 | struct Charity {
12 | string id;
13 | string name;
14 | address payable wallet;
15 | uint256 totalDonations;
16 | bool isActive;
17 | }
18 |
19 | // Mapping to store charities by ID
20 | mapping(string => Charity) public charities;
21 |
22 | // Event to log donations
23 | event DonationReceived(address indexed donor, string indexed charityId, uint256 amount);
24 | event CharityAdded(string indexed charityId, string name, address wallet);
25 | event CharityUpdated(string indexed charityId, string name, address wallet, bool isActive);
26 |
27 | // Function to add a new charity
28 | function addCharity(string memory charityId, string memory name, address payable wallet) public onlyOwner {
29 | require(wallet != address(0), "Invalid wallet address");
30 | require(!charities[charityId].isActive, "Charity already exists");
31 |
32 | charities[charityId] = Charity({
33 | id: charityId,
34 | name: name,
35 | wallet: wallet,
36 | totalDonations: 0,
37 | isActive: true
38 | });
39 |
40 | emit CharityAdded(charityId, name, wallet);
41 | }
42 |
43 | // Function to update charity details
44 | function updateCharity(string memory charityId, string memory name, address payable wallet, bool isActive) public onlyOwner {
45 | require(charities[charityId].isActive, "Charity does not exist");
46 |
47 | charities[charityId].name = name;
48 | charities[charityId].wallet = wallet;
49 | charities[charityId].isActive = isActive;
50 |
51 | emit CharityUpdated(charityId, name, wallet, isActive);
52 | }
53 |
54 | // Function to donate to a charity
55 | function donate(string memory charityId) public payable {
56 | require(charities[charityId].isActive, "Charity is not active");
57 | require(msg.value > 0, "Donation must be greater than zero");
58 |
59 | Charity storage charity = charities[charityId];
60 | charity.wallet.transfer(msg.value); // Transfer funds to the charity's wallet
61 | charity.totalDonations = charity.totalDonations.add(msg.value); // Update total donations
62 |
63 | emit DonationReceived(msg.sender, charityId, msg.value);
64 | }
65 |
66 | // Function to get total donations for a charity
67 | function getTotalDonations(string memory charityId) public view returns (uint256) {
68 | require(charities[charityId].isActive, "Charity is not active");
69 | return charities[charityId].totalDonations;
70 | }
71 |
72 | // Function to get charity details
73 | function getCharity(string memory charityId) public view returns (string memory, address, uint256, bool) {
74 | require(charities[charityId].isActive, "Charity is not active");
75 | Charity memory charity = charities[charityId];
76 | return (charity.name, charity.wallet, charity.totalDonations, charity.isActive);
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/blockchain/smartContracts/communityContract.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity ^0.8.0;
3 |
4 | contract CommunityContract {
5 | struct Member {
6 | address memberAddress;
7 | string name;
8 | uint256 contributions;
9 | bool isActive;
10 | }
11 |
12 | struct Event {
13 | string title;
14 | string description;
15 | uint256 date;
16 | address organizer;
17 | bool isActive;
18 | }
19 |
20 | mapping(address => Member) public members; // Mapping of member address to Member
21 | mapping(uint256 => Event) public events; // Mapping of event ID to Event
22 | uint256 public eventCount; // Counter for the number of events
23 |
24 | event MemberJoined(address indexed memberAddress, string name);
25 | event MemberUpdated(address indexed memberAddress, string name, bool isActive);
26 | event EventCreated(uint256 indexed eventId, string title, address indexed organizer);
27 | event EventUpdated(uint256 indexed eventId, string title, bool isActive);
28 |
29 | modifier onlyActiveMember() {
30 | require(members[msg.sender].isActive, "Not an active member");
31 | _;
32 | }
33 |
34 | // Function to join the community
35 | function joinCommunity(string memory name) public {
36 | require(members[msg.sender].memberAddress == address(0), "Already a member");
37 | members[msg.sender] = Member(msg.sender, name, 0, true);
38 | emit MemberJoined(msg.sender, name);
39 | }
40 |
41 | // Function to update member details
42 | function updateMember(string memory name, bool isActive) public onlyActiveMember {
43 | Member storage member = members[msg.sender];
44 | member.name = name;
45 | member.isActive = isActive;
46 | emit MemberUpdated(msg.sender, name, isActive);
47 | }
48 |
49 | // Function to create a new event
50 | function createEvent(string memory title, string memory description, uint256 date) public onlyActiveMember {
51 | eventCount++;
52 | events[eventCount] = Event(title, description, date, msg.sender, true);
53 | emit EventCreated(eventCount, title, msg.sender);
54 | }
55 |
56 | // Function to update an existing event
57 | function updateEvent(uint256 eventId, string memory title, bool isActive) public {
58 | Event storage eventDetail = events[eventId];
59 | require(msg.sender == eventDetail.organizer, "Not the event organizer");
60 | eventDetail.title = title;
61 | eventDetail.isActive = isActive;
62 | emit EventUpdated(eventId, title, isActive);
63 | }
64 |
65 | // Function to get member details
66 | function getMember(address memberAddress) public view returns (string memory name, uint256 contributions, bool isActive) {
67 | Member memory member = members[memberAddress];
68 | return (member.name, member.contributions, member.isActive);
69 | }
70 |
71 | // Function to get event details
72 | function getEvent(uint256 eventId) public view returns (string memory title, string memory description, uint256 date, address organizer, bool isActive) {
73 | Event memory eventDetail = events[eventId];
74 | return (eventDetail.title, eventDetail.description, eventDetail.date, eventDetail.organizer, eventDetail.isActive);
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/tests/unit/aiController.test.js:
--------------------------------------------------------------------------------
1 | // aiController.test.js
2 |
3 | const aiController = require('./aiController'); // Import the AI controller
4 | const { UserModel } = require('../models/userModel'); // Mock User model
5 | const { TransactionModel } = require('../models/transactionModel'); // Mock Transaction model
6 |
7 | // Mocking the UserModel and TransactionModel
8 | jest.mock('../models/userModel');
9 | jest.mock('../models/transactionModel');
10 |
11 | describe('AI Controller', () => {
12 | beforeEach(() => {
13 | jest.clearAllMocks(); // Clear mocks before each test
14 | });
15 |
16 | describe('generateRecommendations', () => {
17 | it('should return recommendations for a user', async () => {
18 | // Arrange
19 | const userId = '12345';
20 | const mockInteractions = [
21 | { features: [1, 2, 3], label: 1, itemId: 'item1' },
22 | { features: [4, 5, 6], label: 0, itemId: 'item2' },
23 | ];
24 | UserModel.findById.mockResolvedValue({ interactions: mockInteractions });
25 |
26 | // Act
27 | const recommendations = await aiController.generateRecommendations(userId);
28 |
29 | // Assert
30 | expect(recommendations).toBeDefined();
31 | expect(recommendations.length).toBe(2); // Assuming we expect 2 recommendations
32 | expect(recommendations[0]).toHaveProperty('itemId');
33 | expect(recommendations[0]).toHaveProperty('score');
34 | });
35 | });
36 |
37 | describe('analyzeSentiment', () => {
38 | it('should return a sentiment score for a given text', () => {
39 | // Arrange
40 | const text = 'I love this product!';
41 | const expectedScore = 3; // Assuming a positive sentiment score
42 |
43 | // Act
44 | const score = aiController.analyzeSentiment(text);
45 |
46 | // Assert
47 | expect(score).toBe(expectedScore);
48 | });
49 | });
50 |
51 | describe('detectFraud', () => {
52 | it('should detect fraudulent transactions based on amount', async () => {
53 | // Arrange
54 | const transactionId = 'txn123';
55 | const mockTransaction = { amount: 15000 }; // Amount exceeds threshold
56 | TransactionModel.findById.mockResolvedValue(mockTransaction);
57 |
58 | // Act
59 | const result = await aiController.detectFraud(transactionId);
60 |
61 | // Assert
62 | expect(result).toEqual({
63 | isFraudulent: true,
64 | message: 'Transaction amount exceeds threshold.',
65 | });
66 | });
67 |
68 | it('should not detect fraud for normal transactions', async () => {
69 | // Arrange
70 | const transactionId = 'txn456';
71 | const mockTransaction = { amount: 5000 }; // Amount is normal
72 | TransactionModel.findById.mockResolvedValue(mockTransaction);
73 |
74 | // Act
75 | const result = await aiController.detectFraud(transactionId);
76 |
77 | // Assert
78 | expect(result).toEqual({
79 | isFraudulent: false,
80 | message: 'Transaction is normal.',
81 | });
82 | });
83 | });
84 | });
85 |
--------------------------------------------------------------------------------
/src/frontend/js/notification.js:
--------------------------------------------------------------------------------
1 | // src/frontend/js/notification.js
2 |
3 | // Function to fetch notifications for a specific user
4 | const fetchUser Notifications = async (userId) => {
5 | try {
6 | const response = await fetch(`/api/notifications/${userId}`, {
7 | method: 'GET',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | },
11 | });
12 |
13 | if (!response.ok) {
14 | throw new Error('Failed to fetch notifications');
15 | }
16 |
17 | const notifications = await response.json();
18 | return notifications; // Return the list of notifications
19 | } catch (error) {
20 | console.error('Error fetching notifications:', error);
21 | throw new Error('Failed to load notifications. Please try again later.');
22 | }
23 | };
24 |
25 | // Function to send a notification
26 | const sendNotification = async (userId, message) => {
27 | try {
28 | const response = await fetch(`/api/notifications`, {
29 | method: 'POST',
30 | headers: {
31 | 'Content-Type': 'application/json',
32 | },
33 | body: JSON.stringify({ userId, message }),
34 | });
35 |
36 | if (!response.ok) {
37 | throw new Error('Failed to send notification');
38 | }
39 |
40 | const result = await response.json();
41 | return result; // Return the sent notification
42 | } catch (error) {
43 | console.error('Error sending notification:', error);
44 | throw new Error('Failed to send notification. Please try again later.');
45 | }
46 | };
47 |
48 | // Function to mark a notification as read
49 | const markNotificationAsRead = async (notificationId) => {
50 | try {
51 | const response = await fetch(`/api/notifications/${notificationId}/read`, {
52 | method: 'PUT',
53 | headers: {
54 | 'Content-Type': 'application/json',
55 | },
56 | });
57 |
58 | if (!response.ok) {
59 | throw new Error('Failed to mark notification as read');
60 | }
61 |
62 | const updatedNotification = await response.json();
63 | return updatedNotification; // Return the updated notification
64 | } catch (error) {
65 | console.error('Error marking notification as read:', error);
66 | throw new Error('Failed to mark notification as read. Please try again later.');
67 | }
68 | };
69 |
70 | // Function to delete a notification
71 | const deleteNotification = async (notificationId) => {
72 | try {
73 | const response = await fetch(`/api/notifications/${notificationId}`, {
74 | method: 'DELETE',
75 | headers: {
76 | 'Content-Type': 'application/json',
77 | },
78 | });
79 |
80 | if (!response.ok) {
81 | throw new Error('Failed to delete notification');
82 | }
83 |
84 | return true; // Return true if deletion was successful
85 | } catch (error) {
86 | console.error('Error deleting notification:', error);
87 | throw new Error('Failed to delete notification. Please try again later.');
88 | }
89 | };
90 |
91 | // Exporting the notification functions
92 | export {
93 | fetchUser Notifications,
94 | sendNotification,
95 | markNotificationAsRead,
96 | deleteNotification,
97 | };
98 |
--------------------------------------------------------------------------------
/src/backend/services/fraudService.js:
--------------------------------------------------------------------------------
1 | // fraudService.js
2 |
3 | const FraudModel = require('../models/fraudModel');
4 | const TransactionModel = require('../models/transactionModel');
5 | const UserModel = require('../models/userModel');
6 |
7 | class FraudService {
8 | // Log a fraud report
9 | async logFraudReport(userId, transactionId, reason) {
10 | const transaction = await TransactionModel.findById(transactionId);
11 | if (!transaction) {
12 | throw new Error('Transaction not found');
13 | }
14 |
15 | const fraudReport = new FraudModel({
16 | userId,
17 | transactionId,
18 | reportedBy: userId,
19 | reason,
20 | status: 'pending',
21 | });
22 |
23 | await fraudReport.save();
24 | return fraudReport;
25 | }
26 |
27 | // Analyze recent transactions for potential fraud
28 | async analyzeTransactions() {
29 | const transactions = await TransactionModel.find().sort({ createdAt: -1 }).limit(100); // Get the last 100 transactions
30 | const fraudAlerts = [];
31 |
32 | for (const transaction of transactions) {
33 | const isFraudulent = this.isTransactionFraudulent(transaction);
34 | if (isFraudulent) {
35 | fraudAlerts.push(transaction);
36 | await this.createFraudAlert(transaction); // Create a fraud alert if detected
37 | }
38 | }
39 |
40 | return fraudAlerts;
41 | }
42 |
43 | // Check if a transaction is fraudulent (placeholder logic)
44 | isTransactionFraudulent(transaction) {
45 | // Implement your fraud detection logic here (e.g., anomaly detection, rule-based checks)
46 | // Example: Check if the transaction amount exceeds a certain threshold
47 | return transaction.amount > 10000; // Placeholder condition
48 | }
49 |
50 | // Create a fraud alert
51 | async createFraudAlert(transaction) {
52 | const fraudAlert = new FraudModel({
53 | transactionId: transaction._id,
54 | userId: transaction.userId,
55 | reason: 'Suspicious transaction amount',
56 | status: 'investigating',
57 | });
58 |
59 | await fraudAlert.save();
60 | }
61 |
62 | // Get fraud reports by user
63 | async getFraudReportsByUser (userId) {
64 | return await FraudModel.find({ userId }).populate('transactionId').populate('reportedBy', 'username');
65 | }
66 |
67 | // Take action on a fraud alert
68 | async takeActionOnFraudAlert(alertId, action) {
69 | const fraudAlert = await FraudModel.findById(alertId);
70 | if (!fraudAlert) {
71 | throw new Error('Fraud alert not found');
72 | }
73 |
74 | // Update the status based on the action taken
75 | if (action === 'investigate') {
76 | fraudAlert.status = 'investigating';
77 | } else if (action === 'dismiss') {
78 | fraudAlert.status = 'dismissed';
79 | } else if (action === 'resolve') {
80 | fraudAlert.status = 'resolved';
81 | }
82 |
83 | await fraudAlert.save();
84 | return fraudAlert;
85 | }
86 |
87 | // Get all fraud alerts (admin only)
88 | async getAllFraudAlerts() {
89 | return await FraudModel.find().populate('transactionId').populate('reportedBy', 'username');
90 | }
91 | }
92 |
93 | module.exports = new FraudService();
94 |
--------------------------------------------------------------------------------
/docs/setup.md:
--------------------------------------------------------------------------------
1 | # PiConnect Ecosystem - Setup Instructions
2 |
3 | Welcome to the PiConnect Ecosystem project! This document provides step-by-step instructions for setting up the development environment.
4 |
5 | ## Prerequisites
6 |
7 | Before you begin, ensure you have the following installed on your machine:
8 |
9 | - **Node.js** (version 14 or higher)
10 | - **npm** (Node Package Manager, comes with Node.js)
11 | - **Git** (for version control)
12 |
13 | ## Getting Started
14 |
15 | Follow these steps to set up the project:
16 |
17 | ### 1. Clone the Repository
18 |
19 | Open your terminal and run the following command to clone the repository:
20 |
21 | ```bash
22 | git clone https://github.com/KOSASIH/piconnect-ecosystem.git
23 | ```
24 |
25 | Replace `yourusername` with your GitHub username.
26 |
27 | ### 2. Navigate to the Project Directory
28 |
29 | Change into the project directory:
30 |
31 | ```bash
32 | cd piconnect-ecosystem
33 | ```
34 |
35 | ### 3. Install Dependencies
36 |
37 | Install the required dependencies for both the frontend and backend:
38 |
39 | ```bash
40 | # For the frontend
41 | cd src/frontend
42 | npm install
43 |
44 | # For the backend
45 | cd ../backend
46 | npm install
47 | ```
48 |
49 | ### 4. Configure Environment Variables
50 |
51 | Create a `.env` file in the `src/backend` directory and add the necessary environment variables. Here’s an example:
52 |
53 | ```env
54 | PORT=5000
55 | MONGODB_URI=mongodb://localhost:27017/piconnect
56 | JWT_SECRET=your_jwt_secret
57 | ```
58 |
59 | Make sure to replace the values with your actual configuration.
60 |
61 | ### 5. Start the Development Servers
62 |
63 | You can start both the frontend and backend servers. Open two terminal windows or tabs:
64 |
65 | **Terminal 1** (Backend):
66 |
67 | ```bash
68 | cd src/backend
69 | npm start
70 | ```
71 |
72 | **Terminal 2** (Frontend):
73 |
74 | ```bash
75 | cd src/frontend
76 | npm start
77 | ```
78 |
79 | ### 6. Access the Application
80 |
81 | Once both servers are running, you can access the application in your web browser at:
82 |
83 | ```
84 | http://localhost:3000
85 | ```
86 |
87 | ### 7. Running Tests
88 |
89 | To run tests for the frontend and backend, use the following commands:
90 |
91 | **Frontend Tests:**
92 |
93 | ```bash
94 | cd src/frontend
95 | npm test
96 | ```
97 |
98 | **Backend Tests:**
99 |
100 | ```bash
101 | cd src/backend
102 | npm test
103 | ```
104 |
105 | ### 8. Building for Production
106 |
107 | To create a production build of the frontend application, run the following command in the `src/frontend` directory:
108 |
109 | ```bash
110 | npm run build
111 | ```
112 |
113 | This will generate a `dist` folder containing the optimized production files.
114 |
115 | ### 9. Deployment
116 |
117 | Refer to the `deploy.js` script in the `src/frontend/scripts` directory for deployment instructions.
118 |
119 | ## Troubleshooting
120 |
121 | If you encounter any issues during setup, please check the following:
122 |
123 | - Ensure that all dependencies are installed correctly.
124 | - Verify that your environment variables are set up properly.
125 | - Check the console for any error messages and address them accordingly.
126 |
127 | ## Conclusion
128 |
129 | You are now ready to start developing with the PiConnect Ecosystem! If you have any questions or need further assistance, feel free to reach out to the project maintainers.
130 |
131 | Happy coding!
132 |
--------------------------------------------------------------------------------
/src/frontend/js/user.js:
--------------------------------------------------------------------------------
1 | // src/frontend/js/user.js
2 |
3 | // Function to register a new user
4 | const registerUser = async (username, password, email) => {
5 | try {
6 | const response = await fetch('/api/users/register', {
7 | method: 'POST',
8 | headers: {
9 | 'Content-Type': 'application/json',
10 | },
11 | body: JSON.stringify({ username, password, email }),
12 | });
13 |
14 | if (!response.ok) {
15 | throw new Error('Registration failed');
16 | }
17 |
18 | const result = await response.json();
19 | return result; // Return the registered user data
20 | } catch (error) {
21 | console.error('Error registering user:', error);
22 | throw new Error('Failed to register user. Please try again later.');
23 | }
24 | };
25 |
26 | // Function to log in a user
27 | const loginUser = async (username, password) => {
28 | try {
29 | const response = await fetch('/api/users/login', {
30 | method: 'POST',
31 | headers: {
32 | 'Content-Type': 'application/json',
33 | },
34 | body: JSON.stringify({ username, password }),
35 | });
36 |
37 | if (!response.ok) {
38 | throw new Error('Login failed');
39 | }
40 |
41 | const result = await response.json();
42 | return result; // Return the logged-in user data and token
43 | } catch (error) {
44 | console.error('Error logging in user:', error);
45 | throw new Error('Failed to log in. Please check your credentials and try again.');
46 | }
47 | };
48 |
49 | // Function to fetch user details
50 | const fetchUser Details = async (userId) => {
51 | try {
52 | const response = await fetch(`/api/users/${userId}`, {
53 | method: 'GET',
54 | headers: {
55 | 'Content-Type': 'application/json',
56 | },
57 | });
58 |
59 | if (!response.ok) {
60 | throw new Error('Failed to fetch user details');
61 | }
62 |
63 | const userDetails = await response.json();
64 | return userDetails; // Return the user details
65 | } catch (error) {
66 | console.error('Error fetching user details:', error);
67 | throw new Error('Failed to fetch user details. Please try again later.');
68 | }
69 | };
70 |
71 | // Function to update user information
72 | const updateUser = async (userId, updates) => {
73 | try {
74 | const response = await fetch(`/api/users/${userId}`, {
75 | method: 'PUT',
76 | headers: {
77 | 'Content-Type': 'application/json',
78 | },
79 | body: JSON.stringify(updates),
80 | });
81 |
82 | if (!response.ok) {
83 | throw new Error('Failed to update user information');
84 | }
85 |
86 | const updatedUser = await response.json();
87 | return updatedUser ; // Return the updated user data
88 | } catch (error) {
89 | console.error('Error updating user information:', error);
90 | throw new Error('Failed to update user information. Please try again later.');
91 | }
92 | };
93 |
94 | // Exporting the user functions
95 | export {
96 | registerUser ,
97 | loginUser ,
98 | fetchUser Details,
99 | updateUser ,
100 | };
101 |
--------------------------------------------------------------------------------
/ai/fraudDetection.js:
--------------------------------------------------------------------------------
1 | const { createClient } = require('redis');
2 | const { RandomForestClassifier } = require('ml-random-forest');
3 | const { Matrix } = require('ml-matrix');
4 | const axios = require('axios');
5 |
6 | class FraudDetection {
7 | constructor(redisUrl, modelPath) {
8 | this.redisClient = createClient({ url: redisUrl });
9 | this.model = null;
10 | this.modelPath = modelPath;
11 | this.init();
12 | }
13 |
14 | // Initialize the Redis client and load the model
15 | async init() {
16 | await this.redisClient.connect();
17 | console.log('Connected to Redis');
18 | this.model = await this.loadModel();
19 | }
20 |
21 | // Load the pre-trained model
22 | async loadModel() {
23 | // Load the model from the specified path (this is a placeholder)
24 | // In practice, you would use a library to load your model
25 | return new RandomForestClassifier(); // Placeholder for the actual model loading
26 | }
27 |
28 | // Function to fetch transaction data from the blockchain
29 | async fetchTransactionData() {
30 | try {
31 | const response = await axios.get('https://api.example.com/transactions'); // Replace with actual API
32 | return response.data.transactions; // Assuming the API returns an array of transactions
33 | } catch (error) {
34 | console.error('Error fetching transaction data:', error.message);
35 | return [];
36 | }
37 | }
38 |
39 | // Function to preprocess the transaction data
40 | preprocessData(transactions) {
41 | return transactions.map(transaction => {
42 | return [
43 | transaction.amount,
44 | transaction.timestamp,
45 | transaction.sender,
46 | transaction.receiver,
47 | // Add more features as needed
48 | ];
49 | });
50 | }
51 |
52 | // Function to predict fraud for new transactions
53 | async predictFraud(transactions) {
54 | const processedData = this.preprocessData(transactions);
55 | const predictions = this.model.predict(new Matrix(processedData));
56 | return predictions;
57 | }
58 |
59 | // Function to log predictions to Redis
60 | async logPredictions(transactions, predictions) {
61 | for (let i = 0; i < transactions.length; i++) {
62 | await this.redisClient.hSet(`transaction:${transactions[i].id}`, {
63 | isFraud: predictions[i],
64 | ...transactions[i],
65 | });
66 | console.log(`Logged prediction for transaction ${transactions[i].id}`);
67 | }
68 | }
69 |
70 | // Function to close the Redis connection
71 | async close() {
72 | await this.redisClient.quit();
73 | console.log('Disconnected from Redis');
74 | }
75 | }
76 |
77 | // Example usage
78 | const redisUrl = 'redis://localhost:6379';
79 | const fraudDetection = new FraudDetection(redisUrl, './models/fraudDetectionModel');
80 |
81 | // Fetch transactions and predict fraud
82 | fraudDetection.fetchTransactionData()
83 | .then(transactions => {
84 | return fraudDetection.predictFraud(transactions);
85 | })
86 | .then(predictions => {
87 | console.log('Fraud Predictions:', predictions);
88 | return fraudDetection.logPredictions(transactions, predictions);
89 | })
90 | .catch(error => {
91 | console.error('Error in fraud detection process:', error);
92 | });
93 |
94 | // Export the FraudDetection class
95 | module.exports = FraudDetection;
96 |
--------------------------------------------------------------------------------
/src/backend/utils/notificationUtils.js:
--------------------------------------------------------------------------------
1 | // notificationUtils.js
2 |
3 | const nodemailer = require('nodemailer'); // For sending email notifications
4 | const { UserModel } = require('../models/userModel'); // Assuming a User model exists
5 |
6 | // Function to create a notification message
7 | const createNotificationMessage = (type, data) => {
8 | switch (type) {
9 | case 'event_registration':
10 | return `You have successfully registered for the event: ${data.eventTitle}.`;
11 | case 'event_reminder':
12 | return `Reminder: The event "${data.eventTitle}" is happening on ${data.eventDate}.`;
13 | case 'fraud_alert':
14 | return `Alert: Suspicious activity detected on your account. Please check your recent transactions.`;
15 | case 'community_post':
16 | return `New post in the community: "${data.postTitle}" by ${data.username}.`;
17 | default:
18 | return 'You have a new notification.';
19 | }
20 | };
21 |
22 | // Function to send email notifications
23 | const sendEmailNotification = async (to, subject, message) => {
24 | const transporter = nodemailer.createTransport({
25 | service: 'Gmail', // Use your email service
26 | auth: {
27 | user: process.env.EMAIL_USER, // Your email address
28 | pass: process.env.EMAIL_PASS, // Your email password
29 | },
30 | });
31 |
32 | const mailOptions = {
33 | from: process.env.EMAIL_USER,
34 | to,
35 | subject,
36 | text: message,
37 | };
38 |
39 | try {
40 | await transporter.sendMail(mailOptions);
41 | console.log('Email sent successfully to:', to);
42 | } catch (error) {
43 | console.error('Error sending email:', error);
44 | }
45 | };
46 |
47 | // Function to send push notifications (placeholder for actual implementation)
48 | const sendPushNotification = (userId, title, message) => {
49 | // Placeholder for push notification logic
50 | console.log(`Push notification sent to user ${userId}: ${title} - ${message}`);
51 | };
52 |
53 | // Function to log notifications to the database
54 | const logNotificationToDatabase = async (userId, type, message) => {
55 | const notification = new NotificationModel({
56 | userId,
57 | type,
58 | message,
59 | createdAt: new Date(),
60 | });
61 |
62 | await notification.save();
63 | };
64 |
65 | // Function to get user notification preferences
66 | const getUser NotificationPreferences = async (userId) => {
67 | const user = await UserModel.findById(userId);
68 | return user.notificationPreferences; // Assuming preferences are stored in the User model
69 | };
70 |
71 | // Function to send notifications based on user preferences
72 | const notifyUser = async (userId, type, data) => {
73 | const preferences = await getUser NotificationPreferences(userId);
74 | const message = createNotificationMessage(type, data);
75 |
76 | if (preferences.email) {
77 | const user = await UserModel.findById(userId);
78 | await sendEmailNotification(user.email, 'New Notification', message);
79 | }
80 |
81 | if (preferences.push) {
82 | sendPushNotification(userId, 'New Notification', message);
83 | }
84 |
85 | // Log the notification to the database
86 | await logNotificationToDatabase(userId, type, message);
87 | };
88 |
89 | module.exports = {
90 | createNotificationMessage,
91 | sendEmailNotification,
92 | sendPushNotification,
93 | logNotificationToDatabase,
94 | getUser NotificationPreferences,
95 | notifyUser ,
96 | };
97 |
--------------------------------------------------------------------------------
/src/frontend/components/CommunityFeed.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import axios from 'axios';
3 | import './CommunityFeed.css'; // Import CSS for styling
4 |
5 | const CommunityFeed = () => {
6 | const [posts, setPosts] = useState([]);
7 | const [loading, setLoading] = useState(true);
8 | const [error, setError] = useState(null);
9 | const [newComment, setNewComment] = useState('');
10 |
11 | // Fetch community posts from the backend
12 | const fetchPosts = async () => {
13 | try {
14 | const response = await axios.get('/api/posts'); // Adjust the API endpoint as needed
15 | setPosts(response.data);
16 | } catch (err) {
17 | setError('Failed to fetch posts. Please try again later.');
18 | } finally {
19 | setLoading(false);
20 | }
21 | };
22 |
23 | // Handle liking a post
24 | const handleLike = async (postId) => {
25 | try {
26 | await axios.post(`/api/posts/${postId}/like`);
27 | fetchPosts(); // Refresh posts after liking
28 | } catch (err) {
29 | console.error('Failed to like the post:', err);
30 | }
31 | };
32 |
33 | // Handle adding a comment
34 | const handleCommentSubmit = async (postId) => {
35 | if (!newComment.trim()) return; // Prevent empty comments
36 | try {
37 | await axios.post(`/api/posts/${postId}/comments`, { content: newComment });
38 | setNewComment(''); // Clear the input
39 | fetchPosts(); // Refresh posts after commenting
40 | } catch (err) {
41 | console.error('Failed to add comment:', err);
42 | }
43 | };
44 |
45 | useEffect(() => {
46 | fetchPosts();
47 | }, []);
48 |
49 | if (loading) {
50 | return Loading community posts...
;
51 | }
52 |
53 | if (error) {
54 | return {error}
;
55 | }
56 |
57 | return (
58 |
59 |
Community Feed
60 | {posts.length === 0 ? (
61 |
No posts available.
62 | ) : (
63 |
64 | {posts.map((post) => (
65 | -
66 |
{post.title}
67 | {post.content}
68 |
69 |
70 |
Comments
71 |
72 | {post.comments.map((comment) => (
73 | -
74 |
{comment.content}
75 |
76 | ))}
77 |
78 |
setNewComment(e.target.value)}
82 | placeholder="Add a comment..."
83 | />
84 |
85 |
86 |
87 | ))}
88 |
89 | )}
90 |
91 | );
92 | };
93 |
94 | export default CommunityFeed;
95 |
--------------------------------------------------------------------------------
/src/backend/utils/validationService.js:
--------------------------------------------------------------------------------
1 | // validationService.js
2 |
3 | const { body, param, validationResult } = require('express-validator');
4 |
5 | // Function to validate user registration input
6 | const validateUser Registration = () => {
7 | return [
8 | body('username')
9 | .trim()
10 | .notEmpty()
11 | .withMessage('Username is required.')
12 | .isLength({ min: 3, max: 30 })
13 | .withMessage('Username must be between 3 and 30 characters long.'),
14 | body('email')
15 | .trim()
16 | .notEmpty()
17 | .withMessage('Email is required.')
18 | .isEmail()
19 | .withMessage('Invalid email format.'),
20 | body('password')
21 | .notEmpty()
22 | .withMessage('Password is required.')
23 | .isLength({ min: 6 })
24 | .withMessage('Password must be at least 6 characters long.'),
25 | ];
26 | };
27 |
28 | // Function to validate user login input
29 | const validateUser Login = () => {
30 | return [
31 | body('email')
32 | .trim()
33 | .notEmpty()
34 | .withMessage('Email is required.')
35 | .isEmail()
36 | .withMessage('Invalid email format.'),
37 | body('password')
38 | .notEmpty()
39 | .withMessage('Password is required.'),
40 | ];
41 | };
42 |
43 | // Function to validate event creation input
44 | const validateEventInput = () => {
45 | return [
46 | body('title')
47 | .trim()
48 | .notEmpty()
49 | .withMessage('Event title is required.')
50 | .isLength({ max: 100 })
51 | .withMessage('Event title must be at most 100 characters long.'),
52 | body('description')
53 | .trim()
54 | .notEmpty()
55 | .withMessage('Event description is required.')
56 | .isLength({ max: 2000 })
57 | .withMessage('Event description must be at most 2000 characters long.'),
58 | body('date')
59 | .isISO8601()
60 | .withMessage('Event date must be a valid date.'),
61 | body('location')
62 | .trim()
63 | .notEmpty()
64 | .withMessage('Event location is required.'),
65 | body('capacity')
66 | .isInt({ min: 1 })
67 | .withMessage('Event capacity must be a positive integer.'),
68 | ];
69 | };
70 |
71 | // Function to validate registration for an event
72 | const validateRegistrationInput = () => {
73 | return [
74 | body('eventId')
75 | .trim()
76 | .notEmpty()
77 | .withMessage('Event ID is required.'),
78 | ];
79 | };
80 |
81 | // Function to validate fraud report input
82 | const validateFraudReportInput = () => {
83 | return [
84 | body('transactionId')
85 | .trim()
86 | .notEmpty()
87 | .withMessage('Transaction ID is required.'),
88 | body('reason')
89 | .trim()
90 | .notEmpty()
91 | .withMessage('Reason for reporting fraud is required.'),
92 | ];
93 | };
94 |
95 | // Function to validate input and return errors
96 | const validateInput = (req, res, next) => {
97 | const errors = validationResult(req);
98 | if (!errors.isEmpty()) {
99 | return res.status(400).json({ success: false, errors: errors.array() });
100 | }
101 | next();
102 | };
103 |
104 | module.exports = {
105 | validateUser Registration,
106 | validateUser Login,
107 | validateEventInput,
108 | validateRegistrationInput,
109 | validateFraudReportInput,
110 | validateInput,
111 | };
112 |
--------------------------------------------------------------------------------
/blockchain/blockchainService.js:
--------------------------------------------------------------------------------
1 | const Web3 = require('web3');
2 | const { Transaction } = require('ethereumjs-tx').Transaction;
3 | const Common = require('ethereumjs-common').default;
4 | const dotenv = require('dotenv');
5 |
6 | dotenv.config(); // Load environment variables from .env file
7 |
8 | // Initialize Web3
9 | const web3 = new Web3(new Web3.providers.HttpProvider(process.env.BLOCKCHAIN_NODE_URL));
10 |
11 | // Smart contract ABI and address
12 | const contractABI = [ /* ABI array */ ];
13 | const contractAddress = process.env.CONTRACT_ADDRESS;
14 |
15 | // Create contract instance
16 | const contract = new web3.eth.Contract(contractABI, contractAddress);
17 |
18 | // Function to get the balance of an address
19 | async function getBalance(address) {
20 | try {
21 | const balance = await contract.methods.balanceOf(address).call();
22 | return web3.utils.fromWei(balance, 'ether'); // Convert from Wei to Ether
23 | } catch (error) {
24 | console.error('Error fetching balance:', error.message);
25 | throw new Error('Failed to fetch balance. Please try again later.');
26 | }
27 | }
28 |
29 | // Function to send a transaction
30 | async function sendTransaction(fromAddress, toAddress, amount, privateKey) {
31 | try {
32 | const gasPrice = await web3.eth.getGasPrice(); // Get current gas price
33 | const nonce = await web3.eth.getTransactionCount(fromAddress); // Get nonce
34 |
35 | const tx = {
36 | nonce: web3.utils.toHex(nonce),
37 | gasLimit: web3.utils.toHex(21000), // Set gas limit
38 | gasPrice: web3.utils.toHex(gasPrice),
39 | to: toAddress,
40 | value: web3.utils.toHex(web3.utils.toWei(amount.toString(), 'ether')),
41 | };
42 |
43 | const common = Common.forCustomChain(
44 | 'mainnet',
45 | {
46 | name: 'custom',
47 | networkId: 1,
48 | chainId: 1,
49 | },
50 | 'petersburg'
51 | );
52 |
53 | const transaction = new Transaction(tx, { chain: 'mainnet', hardfork: 'petersburg' });
54 | const privateKeyBuffer = Buffer.from(privateKey, 'hex');
55 | transaction.sign(privateKeyBuffer);
56 |
57 | const serializedTx = transaction.serialize();
58 | const receipt = await web3.eth.sendSignedTransaction('0x' + serializedTx.toString('hex'));
59 | return receipt;
60 | } catch (error) {
61 | console.error('Error sending transaction:', error.message);
62 | throw new Error('Transaction failed. Please check your details and try again.');
63 | }
64 | }
65 |
66 | // Function to listen for events from the smart contract
67 | function listenForEvents() {
68 | contract.events.Transfer({
69 | filter: { from: '0xYourAddress' }, // Filter for specific address
70 | fromBlock: 'latest'
71 | })
72 | .on('data', event => {
73 | console.log('Transfer event detected:', event);
74 | })
75 | .on('error', error => {
76 | console.error('Error listening for events:', error.message);
77 | });
78 | }
79 |
80 | // Function to monitor transaction status
81 | async function monitorTransaction(txHash) {
82 | try {
83 | const receipt = await web3.eth.getTransactionReceipt(txHash);
84 | if (receipt) {
85 | return receipt;
86 | } else {
87 | throw new Error('Transaction not found. It may still be pending.');
88 | }
89 | } catch (error) {
90 | console.error('Error monitoring transaction:', error.message);
91 | throw new Error('Failed to monitor transaction. Please try again later.');
92 | }
93 | }
94 |
95 | // Export functions
96 | module.exports = {
97 | getBalance,
98 | sendTransaction,
99 | listenForEvents,
100 | monitorTransaction,
101 | };
102 |
--------------------------------------------------------------------------------
/src/backend/services/aiService.js:
--------------------------------------------------------------------------------
1 | // aiService.js
2 |
3 | const AIModel = require('../models/aiModel');
4 | const UserModel = require('../models/userModel');
5 | const TransactionModel = require('../models/transactionModel');
6 | const RecommendationEngine = require('../utils/recommendationEngine'); // Hypothetical utility for generating recommendations
7 | const SentimentAnalysis = require('../utils/sentimentAnalysis'); // Hypothetical utility for sentiment analysis
8 |
9 | class AIService {
10 | // Generate personalized recommendations for a user
11 | async generateRecommendations(userId) {
12 | const userPreferences = await this.getUser Preferences(userId);
13 | const interactionHistory = await this.getUser InteractionHistory(userId);
14 |
15 | // Use a recommendation engine to generate recommendations
16 | const recommendations = RecommendationEngine.generate(userPreferences, interactionHistory);
17 |
18 | // Save recommendations to the database
19 | await this.saveRecommendations(userId, recommendations);
20 |
21 | return recommendations;
22 | }
23 |
24 | // Get user preferences from the database
25 | async getUser Preferences(userId) {
26 | const user = await UserModel.findById(userId);
27 | return user.preferences; // Assuming preferences are stored in the User model
28 | }
29 |
30 | // Get user interaction history from the database
31 | async getUser InteractionHistory(userId) {
32 | return await AIModel.findOne({ userId }).select('interactionHistory');
33 | }
34 |
35 | // Save recommendations to the database
36 | async saveRecommendations(userId, recommendations) {
37 | const aiData = await AIModel.findOneAndUpdate(
38 | { userId },
39 | { recommendations },
40 | { new: true, upsert: true } // Create a new document if it doesn't exist
41 | );
42 | return aiData;
43 | }
44 |
45 | // Analyze user feedback for sentiment
46 | async analyzeSentiment(feedback) {
47 | const sentimentScore = await SentimentAnalysis.analyze(feedback);
48 | return sentimentScore; // Return sentiment score (e.g., positive, negative, neutral)
49 | }
50 |
51 | // Analyze user behavior patterns
52 | async analyzeUser Behavior(userId) {
53 | const interactionHistory = await this.getUser InteractionHistory(userId);
54 | // Perform analysis on interaction history (e.g., clustering, trend analysis)
55 | const analysisResults = this.performBehaviorAnalysis(interactionHistory);
56 | return analysisResults;
57 | }
58 |
59 | // Perform behavior analysis (placeholder for actual analysis logic)
60 | performBehaviorAnalysis(interactionHistory) {
61 | // Implement your analysis logic here (e.g., clustering algorithms, statistical analysis)
62 | return {}; // Return analysis results
63 | }
64 |
65 | // Analyze community engagement data
66 | async analyzeCommunityEngagement(communityId) {
67 | // Fetch community engagement data (e.g., posts, comments)
68 | const engagementData = await this.getCommunityEngagementData(communityId);
69 | // Perform analysis on engagement data
70 | const analysisResults = this.performEngagementAnalysis(engagementData);
71 | return analysisResults;
72 | }
73 |
74 | // Get community engagement data (placeholder for actual data retrieval)
75 | async getCommunityEngagementData(communityId) {
76 | // Fetch data related to community engagement (e.g., posts, comments)
77 | return []; // Return engagement data
78 | }
79 |
80 | // Perform engagement analysis (placeholder for actual analysis logic)
81 | performEngagementAnalysis(engagementData) {
82 | // Implement your analysis logic here (e.g., sentiment analysis, trend analysis)
83 | return {}; // Return analysis results
84 | }
85 | }
86 |
87 | module.exports = new AIService();
88 |
--------------------------------------------------------------------------------
/src/frontend/js/event.js:
--------------------------------------------------------------------------------
1 | // event.js
2 |
3 | const { EventModel } = require('../models/eventModel'); // Model for events
4 | const { RegistrationModel } = require('../models/registrationModel'); // Model for registrations
5 | const { UserModel } = require('../models/userModel'); // Model for users
6 |
7 | // Function to create a new event
8 | const createEvent = async (userId, title, description, date, location, capacity) => {
9 | const newEvent = new EventModel({
10 | userId,
11 | title,
12 | description,
13 | date,
14 | location,
15 | capacity,
16 | createdAt: new Date(),
17 | });
18 | await newEvent.save();
19 | return newEvent;
20 | };
21 |
22 | // Function to get all events
23 | const getAllEvents = async () => {
24 | return await EventModel.find()
25 | .populate('userId', 'username') // Populate user details
26 | .sort({ date: 1 }); // Sort by event date
27 | };
28 |
29 | // Function to get a single event by ID
30 | const getEventById = async (eventId) => {
31 | const event = await EventModel.findById(eventId).populate('userId', 'username');
32 | if (!event) {
33 | throw new Error('Event not found');
34 | }
35 | return event;
36 | };
37 |
38 | // Function to register for an event
39 | const registerForEvent = async (userId, eventId) => {
40 | const event = await EventModel.findById(eventId);
41 | if (!event) {
42 | throw new Error('Event not found');
43 | }
44 | if (event.capacity <= 0) {
45 | throw new Error('Event is fully booked');
46 | }
47 |
48 | const registration = new RegistrationModel({
49 | userId,
50 | eventId,
51 | });
52 | await registration.save();
53 |
54 | // Decrease the event capacity
55 | event.capacity -= 1;
56 | await event.save();
57 |
58 | return registration;
59 | };
60 |
61 | // Function to get registrations for a specific event
62 | const getEventRegistrations = async (eventId) => {
63 | return await RegistrationModel.find({ eventId })
64 | .populate('userId', 'username') // Populate user details
65 | .sort({ createdAt: -1 }); // Sort by registration date
66 | };
67 |
68 | // Function to cancel registration for an event
69 | const cancelRegistration = async (userId, eventId) => {
70 | const registration = await RegistrationModel.findOneAndDelete({ userId, eventId });
71 | if (!registration) {
72 | throw new Error('Registration not found');
73 | }
74 |
75 | // Increase the event capacity
76 | const event = await EventModel.findById(eventId);
77 | event.capacity += 1;
78 | await event.save();
79 |
80 | return { message: 'Registration canceled successfully' };
81 | };
82 |
83 | // Function to delete an event
84 | const deleteEvent = async (eventId, userId) => {
85 | const event = await EventModel.findById(eventId);
86 | if (!event) {
87 | throw new Error('Event not found');
88 | }
89 | if (event.userId.toString() !== userId.toString()) {
90 | throw new Error('You are not authorized to delete this event');
91 | }
92 | await EventModel.findByIdAndDelete(eventId);
93 | return { message: 'Event deleted successfully' };
94 | };
95 |
96 | // Function to update an event
97 | const updateEvent = async (eventId, userId, updates) => {
98 | const event = await EventModel.findById(eventId);
99 | if (!event) {
100 | throw new Error('Event not found');
101 | }
102 | if (event.userId.toString() !== userId.toString()) {
103 | throw new Error('You are not authorized to update this event');
104 | }
105 |
106 | Object.assign(event, updates);
107 | await event.save();
108 | return event;
109 | };
110 |
111 | module.exports = {
112 | createEvent,
113 | getAllEvents,
114 | getEventById,
115 | registerForEvent,
116 | getEventRegistrations,
117 | cancelRegistration,
118 | deleteEvent,
119 | updateEvent,
120 | };
121 |
--------------------------------------------------------------------------------