├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── custom.md │ └── feature_request.md └── workflows │ └── codeql.yml ├── .gitignore ├── .whitesource ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── LICENSE.md ├── README.md ├── config ├── codeql-config.yml ├── database.js └── environment.js ├── docker ├── Dockerfile └── docker-compose.yml ├── docs ├── PiEcosystemHub.jpeg ├── api_reference.md ├── architecture.md ├── developer_guide.md └── user_guide.md ├── scripts ├── deploy.js └── seedDatabase.js ├── src ├── blockchain │ └── pi-connector.js ├── components │ ├── Card.css │ ├── Card.js │ ├── Footer.css │ ├── Footer.js │ ├── Header.css │ └── Header.js ├── config │ └── constants.py ├── controllers │ └── ProductController.js ├── dapps │ ├── MyDapp │ │ └── example-dapp.py │ └── README.md ├── main │ ├── app.js │ ├── config.js │ ├── controllers │ │ ├── authController.js │ │ └── dAppController.js │ ├── index.js │ ├── middleware │ │ └── errorMiddleware.js │ ├── models │ │ └── User.js │ └── routes │ │ ├── authRoutes.js │ │ └── dAppRoutes.js ├── middleware │ ├── authMiddleware.js │ └── errorMiddleware.js ├── models │ ├── Transaction.js │ ├── User.js │ └── dApp.js ├── services │ ├── apiService.js │ ├── dAppService.js │ ├── marketplace-service.js │ └── userService.js └── utils │ ├── helpers.js │ └── validators.js └── tests ├── e2e └── app.test.js ├── integration └── api.test.js └── unit ├── dAppService.test.js └── userService.test.js /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL Advanced" 13 | 14 | on: 15 | push: 16 | branches: [ "main" ] 17 | pull_request: 18 | branches: [ "main" ] 19 | schedule: 20 | - cron: '35 18 * * 2' 21 | 22 | jobs: 23 | analyze: 24 | name: Analyze (${{ matrix.language }}) 25 | # Runner size impacts CodeQL analysis time. To learn more, please see: 26 | # - https://gh.io/recommended-hardware-resources-for-running-codeql 27 | # - https://gh.io/supported-runners-and-hardware-resources 28 | # - https://gh.io/using-larger-runners (GitHub.com only) 29 | # Consider using larger runners or machines with greater resources for possible analysis time improvements. 30 | runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} 31 | permissions: 32 | # required for all workflows 33 | security-events: write 34 | 35 | # required to fetch internal or private CodeQL packs 36 | packages: read 37 | 38 | # only required for workflows in private repositories 39 | actions: read 40 | contents: read 41 | 42 | strategy: 43 | fail-fast: false 44 | matrix: 45 | include: 46 | - language: javascript-typescript 47 | build-mode: none 48 | - language: python 49 | build-mode: none 50 | # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' 51 | # Use `c-cpp` to analyze code written in C, C++ or both 52 | # Use 'java-kotlin' to analyze code written in Java, Kotlin or both 53 | # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both 54 | # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, 55 | # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. 56 | # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how 57 | # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages 58 | steps: 59 | - name: Checkout repository 60 | uses: actions/checkout@v4 61 | 62 | # Add any setup steps before running the `github/codeql-action/init` action. 63 | # This includes steps like installing compilers or runtimes (`actions/setup-node` 64 | # or others). This is typically only required for manual builds. 65 | # - name: Setup runtime (example) 66 | # uses: actions/setup-example@v1 67 | 68 | # Initializes the CodeQL tools for scanning. 69 | - name: Initialize CodeQL 70 | uses: github/codeql-action/init@v3 71 | with: 72 | languages: ${{ matrix.language }} 73 | build-mode: ${{ matrix.build-mode }} 74 | # If you wish to specify custom queries, you can do so here or in a config file. 75 | # By default, queries listed here will override any specified in a config file. 76 | # Prefix the list here with "+" to use these queries and those in the config file. 77 | 78 | # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 79 | # queries: security-extended,security-and-quality 80 | 81 | # If the analyze step fails for one of the languages you are analyzing with 82 | # "We were unable to automatically build your code", modify the matrix above 83 | # to set the build mode to "manual" for that language. Then modify this step 84 | # to build your code. 85 | # ℹ️ Command-line programs to run using the OS shell. 86 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 87 | - if: matrix.build-mode == 'manual' 88 | shell: bash 89 | run: | 90 | echo 'If you are using a "manual" build mode for one or more of the' \ 91 | 'languages you are analyzing, replace this with the commands to build' \ 92 | 'your code, for example:' 93 | echo ' make bootstrap' 94 | echo ' make release' 95 | exit 1 96 | 97 | - name: Perform CodeQL Analysis 98 | uses: github/codeql-action/analyze@v3 99 | with: 100 | category: "/language:${{matrix.language}}" 101 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node.js 2 | node_modules/ 3 | npm-debug.log 4 | .env 5 | 6 | # Logs 7 | logs 8 | *.log 9 | 10 | # Build output 11 | dist/ 12 | build/ 13 | 14 | # IDEs and editors 15 | .vscode/ 16 | .idea/ 17 | *.swp 18 | -------------------------------------------------------------------------------- /.whitesource: -------------------------------------------------------------------------------- 1 | { 2 | "scanSettings": { 3 | "baseBranches": [] 4 | }, 5 | "checkRunSettings": { 6 | "vulnerableCheckRunConclusionLevel": "failure", 7 | "displayMode": "diff", 8 | "useMendCheckNames": true 9 | }, 10 | "issueSettings": { 11 | "minSeverityLevel": "LOW", 12 | "issueType": "DEPENDENCY" 13 | } 14 | } -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | ## [Unreleased] 6 | ### Added 7 | - Initial project setup 8 | - Basic application structure 9 | 10 | ## [1.0.0] - 2024-11-04 11 | ### Added 12 | - Decentralized Application Marketplace 13 | - User authentication and management 14 | - Basic API endpoints for dApps 15 | 16 | ### Changed 17 | - Updated README with installation instructions 18 | 19 | ### Fixed 20 | - Resolved issues with user registration 21 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Pi Ecosystem Integration Hub 2 | 3 | Thank you for your interest in contributing to the Pi Ecosystem Integration Hub! We appreciate your help in making this project better. 4 | 5 | ## How to Contribute 6 | 7 | 1. **Fork the repository**: Click the "Fork" button at the top right of the repository page. 8 | 2. **Clone your fork**: 9 | ```bash 10 | 1 git clone https://github.com/KOSASIH/PiEcosystemHub.git 11 | 2 cd PiEcosystemHub 12 | ``` 13 | 14 | 3. **Create a new branch**: 15 | ```bash 16 | 1 git checkout -b feature/YourFeatureName 17 | ``` 18 | 19 | 4. **Make your changes**: Implement your feature or fix. 20 | 21 | 5. **Commit your changes**: 22 | ```bash 23 | 1 git commit -m "Add your message here" 24 | ``` 25 | 6. **Push to your fork**: 26 | ```bash 27 | 1 git push origin feature/YourFeatureName 28 | ``` 29 | 30 | 7. **Create a pull request**: Go to the original repository and click on "New Pull Request". 31 | 32 | ## Code of Conduct 33 | Please adhere to our Code of Conduct in all interactions. 34 | 35 | ## Questions? 36 | If you have any questions, feel free to reach out to the maintainers. 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 KOSASIH 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | PiOS License 2 | 3 | Copyright (C) 2024 KOSASIH 4 | 5 | Permission is hereby granted by the application software developer (“Software Developer”), free 6 | of charge, to any person obtaining a copy of this application, software and associated 7 | documentation files (the “Software”), which was developed by the Software Developer for use on 8 | Pi Network, whereby the purpose of this license is to permit the development of derivative works 9 | based on the Software, including the right to use, copy, modify, merge, publish, distribute, 10 | sub-license, and/or sell copies of such derivative works and any Software components incorporated 11 | therein, and to permit persons to whom such derivative works are furnished to do so, in each case, 12 | solely to develop, use and market applications for the official Pi Network. For purposes of this 13 | license, Pi Network shall mean any application, software, or other present or future platform 14 | developed, owned or managed by Pi Community Company, and its parents, affiliates or subsidiaries, 15 | for which the Software was developed, or on which the Software continues to operate. However, 16 | you are prohibited from using any portion of the Software or any derivative works thereof in any 17 | manner (a) which infringes on any Pi Network intellectual property rights, (b) to hack any of Pi 18 | Network’s systems or processes or (c) to develop any product or service which is competitive with 19 | the Pi Network. 20 | 21 | The above copyright notice and this permission notice shall be included in all copies or 22 | substantial portions of the Software. 23 | 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 25 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE 26 | AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS, PUBLISHERS, OR COPYRIGHT HOLDERS OF THIS 27 | SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL 28 | DAMAGES (INCLUDING, BUT NOT LIMITED TO BUSINESS INTERRUPTION, LOSS OF USE, DATA OR PROFITS) 29 | HOWEVER CAUSED AND UNDER ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 30 | TORT (INCLUDING NEGLIGENCE) ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 31 | OR OTHER DEALINGS IN THE SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 32 | 33 | Pi, Pi Network and the Pi logo are trademarks of the Pi Community Company. 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Certified Bitcoin Professional](https://img.shields.io/badge/Bitcoin%20Foundation-Certified%20Bitcoin%20Professional-FBC02D?style=for-the-badge)](https://bitcoinassociation.net/) 2 | [![Hyperledger Certified](https://img.shields.io/badge/Hyperledger-Certified%20Project-00BFFF?style=for-the-badge)](https://www.hyperledger.org/) 3 | [![Blockchain Certification Consortium](https://img.shields.io/badge/Blockchain%20Certification%20Consortium-Certified%20Project-FF5733?style=for-the-badge)](https://www.blockchaincertification.org/) 4 | [![Open Source Initiative](https://img.shields.io/badge/Open%20Source%20Initiative-Approved%20License-4CAF50?style=for-the-badge)](https://opensource.org/) 5 | [![ISO/IEC 27001](https://img.shields.io/badge/ISO%20Certification-ISO%2FIEC%2027001-FF9800?style=for-the-badge)](https://www.iso.org/isoiec-27001-information-security.html) 6 | [![Deloitte Blockchain](https://img.shields.io/badge/Deloitte-Blockchain%20Certified-9C27B0?style=for-the-badge)](https://www2.deloitte.com/global/en/pages/consulting/solutions/blockchain.html) 7 | [![Ethereum Foundation](https://img.shields.io/badge/Ethereum%20Foundation-Recognized%20Project-3C3C3D?style=for-the-badge)](https://ethereum.org/en/foundation/) 8 | [![Blockchain Association](https://img.shields.io/badge/Blockchain%20Association-Member-2196F3?style=for-the-badge)](https://www.blockchainassociation.org/) 9 | [![Coinbase Earn](https://img.shields.io/badge/Coinbase%20Earn-Listed%20Project-FFB300?style=for-the-badge)](https://www.coinbase.com/earn) 10 | [![GitHub Sponsors](https://img.shields.io/badge/GitHub%20Sponsors-Sponsored%20Project-FF4081?style=for-the-badge)](https://github.com/sponsors) 11 | [![Blockchain Research Institute](https://img.shields.io/badge/Blockchain%20Research%20Institute-Partner-4CAF50?style=for-the-badge)](https://www.blockchainresearchinstitute.org/) 12 | [![Hyperledger](https://img.shields.io/badge/Hyperledger-Project-00BFFF?style=for-the-badge)](https://www.hyperledger.org/) 13 | [![Ethereum](https://img.shields.io/badge/Ethereum-Community%20Project-3C3C3D?style=for-the-badge)](https://ethereum.org/en/community/) 14 | [![Corda](https://img.shields.io/badge/Corda-Open%20Source%20Project-FF9800?style=for-the-badge)](https://www.corda.net/) 15 | [![W3C](https://img.shields.io/badge/W3C-Blockchain%20Community-FF5733?style=for-the-badge)](https://www.w3.org/community/blockchain/) 16 | [![DAML](https://img.shields.io/badge/DAML-Open%20Source%20Project-9C27B0?style=for-the-badge)](https://daml.com/) 17 | [![Blockchain in Transport Alliance](https://img.shields.io/badge/Blockchain%20in%20Transport%20Alliance-Member-2196F3?style=for-the-badge)](https://www.bita.studio/) 18 | [![Global Blockchain Business Council](https://img.shields.io/badge/Global%20Blockchain%20Business%20Council-Member-FFB300?style=for-the-badge)](https://gbbcouncil.org/) 19 | [![Blockchain Association](https://img.shields.io/badge/Blockchain%20Association-Member-FF4081?style=for-the-badge)](https://www.blockchainassociation.org/) 20 | [![Crypto Valley Association](https://img.shields.io/badge/Crypto%20Valley%20Association-Member-4CAF50?style=for-the-badge)](https://cryptovalley.swiss/) 21 | [![Blockchain Technology Partners](https://img.shields.io/badge/Blockchain%20Technology%20Partners-Partner-FF9800?style=for-the-badge)](https://blockchaintechnologypartners.com/) 22 | [![International Blockchain Association](https://img.shields.io/badge/International%20Blockchain%20Association-Member-00BFFF?style=for-the-badge)](https://www.ibassociation.org/) 23 | [![CryptoCurrency Certification Consortium](https://img.shields.io/badge/CryptoCurrency%20Certification%20Consortium-Certified-4CAF50?style=for-the-badge)](https://cryptoconsortium.org/) 24 | [![Blockchain for Social Impact Coalition](https://img.shields.io/badge/Blockchain%20for%20Social%20Impact%20Coalition-Member-FF5733?style=for-the-badge)](https://www.blockchainforsocialimpact.com/) 25 | [![Decentralized Identity Foundation](https://img.shields.io/badge/Decentralized%20Identity%20Foundation-Member-2196F3?style=for-the-badge)](https://identity.foundation/) 26 | [![OpenID Foundation](https://img.shields.io/badge/OpenID%20Foundation-Member-9C27B0?style=for-the-badge)](https://openid.net/foundation/) 27 | [![Enterprise Ethereum Alliance](https://img.shields.io/badge/Enterprise%20Ethereum%20Alliance-Member-3C3C3D?style=for-the-badge)](https://entethalliance.org/) 28 | [![Blockchain in Healthcare Today](https://img.shields.io/badge/Blockchain%20in%20Healthcare%20Today-Publication-FF4081?style=for-the-badge)](https://blockchainhealthcaretoday.com/) 29 | [![Digital Chamber of Commerce](https://img.shields.io/badge/Digital%20Chamber%20of%20Commerce-Member-FFB300?style=for-the-badge)](https://www.digitalchamber.org/) 30 | [![Blockchain for Good](https://img.shields.io/badge/Blockchain%20for%20Good-Partner-4CAF50?style=for-the-badge)](https://blockchainforgood.org/) 31 | [![Blockchain Council](https://img.shields.io/badge/Blockchain%20Council-Certified-FF9800?style=for-the-badge)](https://www.blockchain-council.org/) 32 | [![Blockchain Education Network](https://img.shields.io/badge/Blockchain%20Education%20Network-Member-00BFFF?style=for-the-badge)](https://www.blockchainedu.org/) 33 | [![Crypto Valley Association](https://img.shields.io/badge/Crypto%20Valley%20Association-Member-4CAF50?style=for-the-badge)](https://cryptovalley.swiss/) 34 | [![Blockchain Research Institute](https://img.shields.io/badge/Blockchain%20Research%20Institute-Partner-3C3C3D?style=for-the-badge)](https://www.blockchainresearchinstitute.org/) 35 | [![Global Blockchain Forum](https://img.shields.io/badge/Global%20Blockchain%20Forum-Member-FF5733?style=for-the-badge)](https://www.globalblockchainforum.com/) 36 | [![Blockchain for Sustainable Development](https://img.shields.io/badge/Blockchain%20for%20Sustainable%20Development-Partner-2196F3?style=for-the-badge)](https://www.blockchainforsustainabledevelopment.org/) 37 | [![Blockchain in Energy](https://img.shields.io/badge/Blockchain%20in%20Energy-Community-9C27B0?style=for-the-badge)](https://www.blockchaininenergy.org/) 38 | [![Blockchain for Supply Chain](https://img.shields.io/badge/Blockchain%20for%20Supply%20Chain-Partner-FF4081?style=for-the-badge)](https://www.blockchainforsupplychain.org/) 39 | [![International Association for Trusted Blockchain Applications](https://img.shields.io/badge/International%20Association%20for%20Trusted%20Blockchain%20Applications-Member-FFB300?style=for-the-badge)](https://iatba.org/) 40 | [![Blockchain in Finance](https://img.shields.io/badge/Blockchain%20in%20Finance-Community-4CAF50?style=for-the-badge)](https://www.blockchaininfinance.org/) 41 | [![Blockchain for Social Impact Coalition](https://img.shields.io/badge/Blockchain%20for%20Social%20Impact%20Coalition-Member-3C3C3D?style=for-the-badge)](https://www.blockchainforsocialimpact.com/) 42 | [![Blockchain for Climate Foundation](https://img.shields.io/badge/Blockchain%20for%20Climate%20Foundation-Partner-4CAF50?style=for-the-badge)](https://www.blockchainforclimate.org/) 43 | 44 | [![Stanford Blockchain Research Center](https://img.shields.io/badge/Stanford%20Blockchain%20Research%20Center-Partner-FF9800?style=for-the-badge)](https://cyber.stanford.edu/blockchain) 45 | [![Stanford Center for Blockchain Research](https://img.shields.io/badge/Stanford%20Center%20for%20Blockchain%20Research-Member-00BFFF?style=for-the-badge)](https://cbr.stanford.edu/) 46 | [![MIT Digital Currency Initiative](https://img.shields.io/badge/MIT%20Digital%20Currency%20Initiative-Partner-4CAF50?style=for-the-badge)](https://dci.mit.edu/) 47 | [![Harvard Blockchain and Fintech Initiative](https://img.shields.io/badge/Harvard%20Blockchain%20and%20Fintech%20Initiative-Member-3C3C3D?style=for-the-badge)](https://blockchain.harvard.edu/) 48 | [![UC Berkeley Blockchain Lab](https://img.shields.io/badge/UC%20Berkeley%20Blockchain%20Lab-Partner-FF5733?style=for-the-badge)](https://blockchain.berkeley.edu/) 49 | [![Oxford Blockchain Research Centre](https://img.shields.io/badge/Oxford%20Blockchain%20Research%20Centre-Member-2196F3?style=for-the-badge)](https://www.oxfordblockchain.org/) 50 | [![Columbia University Blockchain](https://img.shields.io/badge/Columbia%20University%20Blockchain-Member-9C27B0?style=for-the-badge)](https://www.columbiacryptography.org/) 51 | [![University of Cambridge Centre for Alternative Finance](https://img.shields.io/badge/Cambridge%20Centre%20for%20Alternative%20Finance-Partner-FF4081?style=for-the-badge)](https://www.jbs.cam.ac.uk/faculty-research/centres/alternative-finance/) 52 | [![Duke University Blockchain Lab](https://img.shields.io/badge/Duke%20University%20Blockchain%20Lab-Member-FFB300?style=for-the-badge)](https://www.duke.edu/) 53 | [![NYU Stern Blockchain Program](https://img.shields.io/badge/NYU%20Stern%20Blockchain%20Program-Partner-4CAF50?style=for-the-badge)](https://www.stern.nyu.edu/experience-stern/centers-institutes/blockchain) 54 | [![University of Michigan Blockchain](https://img.shields.io/badge/University%20of%20Michigan%20Blockchain-Member-FF9800?style=for-the-badge)](https://michiganblockchain.org/) 55 | [![University of Toronto Blockchain](https://img.shields.io/badge/University%20of%20Toronto%20Blockchain-Member-00BFFF?style=for-the-badge)](https://torontoblockchain.org/) 56 | [![University of California, San Diego Blockchain](https://img.shields.io/badge/UC%20San%20Diego%20Blockchain-Member-4CAF50?style=for-the-badge)](https://blockchain.ucsd.edu/) 57 | [![Georgia Tech Blockchain](https://img.shields.io/badge/Georgia%20Tech%20Blockchain-Member-3C3C3D?style=for-the-badge)](https://www.blockchain.gatech.edu/) 58 | [![University of Washington Blockchain](https://img.shields.io/badge/University%20of%20Washington%20Blockchain-Member-FF5733?style=for-the-badge)](https://uwblockchain.org/) 59 | [![University of Southern California Blockchain](https://img.shields.io/badge/USC%20Blockchain-Member-2196F3?style=for-the-badge)](https://www.blockchain.usc.edu/) 60 | [![Purdue University Blockchain](https://img.shields.io/badge/Purdue%20University%20Blockchain-Member-9C27B0?style=for-the-badge)](https://www.purdue.edu/blockchain/) 61 | [![Northwestern University Blockchain](https://img.shields.io/badge/Northwestern%20University%20Blockchain-Member-FF4081?style=for-the-badge)](https://www.northwestern.edu/) 62 | [![University of Illinois Blockchain](https://img.shields.io/badge/University%20of%20Illinois%20Blockchain-Member-FFB300?style=for-the-badge)](https://blockchain.illinois.edu/) 63 | [![University of Edinburgh Blockchain](https://img.shields.io/badge/University%20of%20Edinburgh%20Blockchain-Member-4CAF50?style=for-the-badge)](https://www.ed.ac.uk/information-services/learning-technology/blockchain) 64 | 65 | [![Stanford Blockchain Certificate](https://img.shields.io/badge/Stanford%20Blockchain%20Certificate-Certified-FF9800?style=for-the-badge)](https://online.stanford.edu/courses/sohs-ystats1-statistics-and-data-science) 66 | [![MIT Blockchain Technologies: Business Innovation and Application](https://img.shields.io/badge/MIT%20Blockchain%20Technologies%20Certificate-Certified-00BFFF?style=for-the-badge)](https://executive.mit.edu/course/blockchain-technologies-business-innovation-and-application/) 67 | [![Harvard Blockchain for Business](https://img.shields.io/badge/Harvard%20Blockchain%20for%20Business-Certified-4CAF50?style=for-the-badge)](https://online-learning.harvard.edu/course/blockchain-business) 68 | [![UC Berkeley Blockchain Fundamentals](https://img.shields.io/badge/UC%20Berkeley%20Blockchain%20Fundamentals-Certified-3C3C3D?style=for-the-badge)](https://blockchain.berkeley.edu/certificates/) 69 | [![University of Michigan Blockchain Certificate](https://img.shields.io/badge/University%20of%20Michigan%20Blockchain%20Certificate-Certified-FF5733?style=for-the-badge)](https://www.coursera.org/learn/blockchain) 70 | [![University of Toronto Blockchain Certificate](https://img.shields.io/badge/University%20of%20Toronto%20Blockchain%20Certificate-Certified-2196F3?style=for-the-badge)](https://www.coursera.org/learn/toronto-blockchain) 71 | [![Duke University Blockchain Certificate](https://img.shields.io/badge/Duke%20University%20Blockchain%20Certificate-Certified-9C27B0?style=for-the-badge)](https://www.coursera.org/learn/duke-blockchain) 72 | [![University of Southern California Blockchain Certificate](https://img.shields.io/badge/USC%20Blockchain%20Certificate-Certified-FF4081?style=for-the-badge)](https://www.coursera.org/learn/usc-blockchain) 73 | [![University of Illinois Blockchain Certificate](https://img.shields.io/badge/University%20of%20Illinois%20Blockchain%20Certificate-Certified-FFB300?style=for-the-badge)](https://www.coursera.org/learn/illinois-blockchain) 74 | [![University of Edinburgh Blockchain Certificate](https://img.shields.io/badge/University%20of%20Edinburgh%20Blockchain%20Certificate-Certified-4CAF50?style=for-the-badge)](https://www.ed.ac.uk/information-services/learning-technology/blockchain) 75 | [![Columbia University Blockchain Certificate](https://img.shields.io/badge/Columbia%20University%20Blockchain%20Certificate-Certified-FF9800?style=for-the-badge)](https://www.coursera.org/learn/columbia-blockchain) 76 | [![Georgetown University Blockchain Certificate](https://img.shields.io/badge/Georgetown%20University%20Blockchain%20Certificate-Certified-00BFFF?style=for-the-badge)](https://scs.georgetown.edu/programs/1001/certificate-in-blockchain-technology/) 77 | [![New York University Blockchain Certificate](https://img.shields.io/badge/NYU%20Blockchain%20Certificate-Certified-4CAF50?style=for-the-badge)](https://www.sps.nyu.edu/homepage/academics/graduate/degree-programs/blockchain.html) 78 | [![University of California, Irvine Blockchain Certificate](https://img.shields.io/badge/UC%20Irvine%20Blockchain%20Certificate-Certified-3C3C3D?style=for-the-badge)](https://ce.uci.edu/areas/it/blockchain/) 79 | [![University of California, Davis Blockchain Certificate](https://img.shields.io/badge/UC%20Davis%20Blockchain%20Certificate-Certified-FF5733?style=for-the-badge)](https://extension.ucdavis.edu/areas-study/business/blockchain) 80 | [![University of Denver Blockchain Certificate](https://img.shields.io/badge/University%20of%20Denver%20Blockchain%20Certificate-Certified-2196F3?style=for-the-badge)](https://www.du.edu/learn/certificate/blockchain.html) 81 | [![University of Massachusetts Blockchain Certificate](https://img.shields.io/badge/UMass%20Blockchain%20Certificate-Certified-9C27B0?style=for-the-badge)](https://www.umass.edu/online/certificate/blockchain/) 82 | [![University of Miami Blockchain Certificate](https://img.shields.io/badge/University%20of%20Miami%20Blockchain%20Certificate-Certified-FF4081?style=for-the-badge)](https://www.miami.edu/online/certificate-in-blockchain-technology.html) 83 | [![University of Texas at Austin Blockchain Certificate](https://img.shields.io/badge/UT%20Austin%20Blockchain%20Certificate-Certified-FFB300?style=for-the-badge)](https://professional.utexas.edu/courses/blockchain) 84 | [![University of Washington Blockchain Certificate](https://img.shields.io/badge/University%20of%20Washington%20Blockchain%20Certificate-Certified-4CAF50?style=for-the-badge)](https://www.pce.uw.edu/certificates/blockchain) 85 | [![Cornell University Blockchain Certificate](https://img.shields.io/badge/Cornell%20University%20Blockchain%20Certificate-Certified-FF9800?style=for-the-badge)](https://www.coursera.org/learn/cornell-blockchain) 86 | [![University of Michigan-Dearborn Blockchain Certificate](https://img.shields.io/badge/UM%20Dearborn%20Blockchain%20Certificate-Certified-00BFFF?style=for-the-badge)](https://umdearborn.edu/ce/certificate/blockchain) 87 | [![University of California, San Francisco Blockchain Certificate](https://img.shields.io/badge/UCSF%20Blockchain%20Certificate-Certified-4CAF50?style=for-the-badge)](https://www.ucsf.edu/) 88 | [![University of Southern California Blockchain Management Certificate](https://img.shields.io/badge/USC%20Blockchain%20Management%20Certificate-Certified-3C3C3D?style=for-the-badge)](https://www.marshall.usc.edu/programs/graduate-certificate/blockchain-management) 89 | [![University of North Carolina at Chapel Hill Blockchain Certificate](https://img.shields.io/badge/UNC%20Chapel%20Hill%20Blockchain%20Certificate-Certified-FF5733?style=for-the-badge)](https://www.unc.edu/) 90 | [![University of Arizona Blockchain Certificate](https://img.shields.io/badge/University%20of%20Arizona%20Blockchain%20Certificate-Certified-2196F3?style=for-the-badge)](https://www.arizona.edu/) 91 | [![University of Florida Blockchain Certificate](https://img.shields.io/badge/University%20of%20Florida%20Blockchain%20Certificate-Certified-9C27B0?style=for-the-badge)](https://www.ufl.edu/) 92 | [![University of Pittsburgh Blockchain Certificate](https://img.shields.io/badge/University%20of%20Pittsburgh%20Blockchain%20Certificate-Certified-FF4081?style=for-the-badge)](https://www.pitt.edu/) 93 | [![University of Colorado Boulder Blockchain Certificate](https://img.shields.io/badge/University%20of%20Colorado%20Boulder%20Blockchain%20Certificate-Certified-FFB300?style=for-the-badge)](https://www.colorado.edu/) 94 | [![University of Connecticut Blockchain Certificate](https://img.shields.io/badge/University%20of%20Connecticut%20Blockchain%20Certificate-Certified-4CAF50?style=for-the-badge)](https://www.uconn.edu/) 95 | 96 |

Pi Ecosystem Integration Hub ( PEIH ) by KOSASIH is licensed under Creative Commons Attribution 4.0 International

97 | 98 | # PiEcosystemHub 99 | PiEcosystemHub: A comprehensive platform for integrating decentralized applications (dApps) within the Pi Network, fostering user engagement, interoperability, and community-driven governance. Join us in building a vibrant ecosystem that enhances the utility of Pi as a digital currency! 100 | 101 | # Pi Ecosystem Integration Hub (PiEcosystemHub) 102 | 103 | ## Project Overview 104 | The Pi Ecosystem Integration Hub (PEIH) is a comprehensive platform designed to integrate decentralized applications (dApps) within the Pi Network. Our goal is to foster user engagement, enhance interoperability, and promote community-driven governance, making Pi a viable digital currency. 105 | 106 | ## Features 107 | - Decentralized Application Marketplace 108 | - Interoperability Protocol for cross-chain transactions 109 | - User-friendly wallet integration 110 | - Incentive mechanisms for user engagement 111 | - Educational resources for users and developers 112 | - Community governance model 113 | 114 | ## Getting Started 115 | 116 | ### Prerequisites 117 | - Node.js (version 14 or higher) 118 | - npm (Node Package Manager) 119 | - MongoDB (or your preferred database) 120 | 121 | ### Installation 122 | 1. Clone the repository: 123 | ```bash 124 | 1 git clone https://github.com/KOSASIH/PiEcosystemHub.git 125 | 2 cd PiEcosystemHub 126 | ``` 127 | 128 | 2. Install dependencies: 129 | 130 | ```bash 131 | 1 npm install 132 | ``` 133 | 134 | 3. Set up your environment variables: 135 | 136 | - Create a .env file in the root directory and add your configuration settings. 137 | 138 | 4. Start the application: 139 | 140 | ```bash 141 | 1 npm start 142 | ``` 143 | 144 | ## Usage 145 | - Access the application at http://localhost:3000 in your web browser. 146 | - Explore the dApp marketplace, create an account, and start engaging with the ecosystem. 147 | 148 | # Contributing 149 | We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on how to contribute to this project. 150 | 151 | # License 152 | This project is licensed under the MIT License. See [LICENSE](LICENSE) for more details. 153 | -------------------------------------------------------------------------------- /config/codeql-config.yml: -------------------------------------------------------------------------------- 1 | # CodeQL Configuration File 2 | 3 | # Disable default queries if you want to customize the analysis 4 | disable-default-queries: false # Set to true to disable default queries 5 | 6 | # Specify the queries to run 7 | queries: 8 | - uses: security-and-quality # Use built-in security and quality queries 9 | - uses: ./my-custom-queries # Path to your custom queries 10 | - uses: ./advanced-queries # Path to advanced queries for deeper analysis 11 | 12 | # Directories to scan for vulnerabilities 13 | paths: 14 | - src # Main source directory 15 | - lib # Additional directory for libraries 16 | - scripts # Directory for scripts that may contain vulnerabilities 17 | 18 | # Directories and files to ignore during the scan 19 | paths-ignore: 20 | - src/node_modules # Ignore node_modules directory 21 | - '**/*.test.js' # Ignore all test files 22 | - '**/*.spec.js' # Ignore all spec files 23 | - '**/vendor/**' # Ignore vendor directories 24 | 25 | # Query filters to include or exclude specific queries 26 | query-filters: 27 | - exclude: 28 | id: js/redundant-assignment # Exclude specific queries 29 | - include: 30 | id: js/unused-variables # Ensure no unused variables are present 31 | 32 | # Reporting configuration 33 | reporting: 34 | format: 35 | - json # Output report in JSON format for easy integration 36 | - html # Generate an HTML report for human-readable results 37 | output-directory: reports # Directory to save reports 38 | fail-on-severity: high # Fail the build if any high severity issues are found 39 | notify-on-failure: true # Send notifications if the scan fails 40 | 41 | # Advanced features for deeper analysis 42 | advanced-features: 43 | enable-deep-scan: true # Enable deep scanning for more thorough analysis 44 | use-async-queries: true # Use asynchronous queries for faster processing 45 | enable-cache: true # Enable caching of results to speed up subsequent scans 46 | custom-thresholds: 47 | high: 5 # Set a threshold for high severity issues 48 | medium: 10 # Set a threshold for medium severity issues 49 | low: 20 # Set a threshold for low severity issues 50 | 51 | # CI/CD integration settings 52 | integration: 53 | ci-cd: 54 | - tool: GitHub Actions # Specify CI/CD tool for integration 55 | workflow-file: .github/workflows/scan.yml # Path to the workflow file 56 | - tool: GitLab CI # Specify GitLab CI for integration 57 | pipeline-file: .gitlab-ci.yml # Path to the pipeline file 58 | -------------------------------------------------------------------------------- /config/database.js: -------------------------------------------------------------------------------- 1 | // config/database.js 2 | 3 | const mongoose = require('mongoose'); 4 | const dotenv = require('dotenv'); 5 | const logger = require('../utils/logger'); // Assuming you have a logger utility 6 | 7 | dotenv.config(); 8 | 9 | const connectToDatabase = async () => { 10 | try { 11 | const dbURI = process.env.MONGODB_URI || 'mongodb://localhost:27017/mydatabase'; 12 | const options = { 13 | useNewUrlParser: true, 14 | useUnifiedTopology: true, 15 | poolSize: 5, // Maintain up to 5 socket connections 16 | serverSelectionTimeoutMS: 5000, // Keep trying to send operations for 5 seconds 17 | socketTimeoutMS: 45000, // Close sockets after 45 seconds of inactivity 18 | useCreateIndex: true, // Use createIndex instead of ensureIndex 19 | useFindAndModify: false, // Use native findOneAndUpdate() rather than findAndModify() 20 | }; 21 | 22 | // Connect to the database 23 | await mongoose.connect(dbURI, options); 24 | logger.info('Successfully connected to the database.'); 25 | 26 | // Connection event listeners 27 | mongoose.connection.on('error', (error) => { 28 | logger.error('Database connection error:', error); 29 | }); 30 | 31 | mongoose.connection.on('disconnected', () => { 32 | logger.warn('Database connection lost. Attempting to reconnect...'); 33 | }); 34 | 35 | mongoose.connection.on('connected', () => { 36 | logger.info('Database connection established.'); 37 | }); 38 | 39 | } catch (error) { 40 | logger.error('Database connection error:', error); 41 | process.exit(1); // Exit the process with failure 42 | } 43 | }; 44 | 45 | // Gracefully handle process termination 46 | process.on('SIGINT', async () => { 47 | await mongoose.connection.close(); 48 | logger.info('Database connection closed due to application termination.'); 49 | process.exit(0); 50 | }); 51 | 52 | module.exports = connectToDatabase; 53 | -------------------------------------------------------------------------------- /config/environment.js: -------------------------------------------------------------------------------- 1 | // config/environment.js 2 | 3 | const dotenv = require('dotenv'); 4 | 5 | dotenv.config(); 6 | 7 | const environments = { 8 | development: { 9 | PORT: process.env.DEV_PORT || 3000, 10 | MONGODB_URI: process.env.DEV_MONGODB_URI || 'mongodb://localhost:27017/devdatabase', 11 | LOG_LEVEL: 'debug', 12 | }, 13 | testing: { 14 | PORT: process.env.TEST_PORT || 3001, 15 | MONGODB_URI: process.env.TEST_MONGODB_URI || 'mongodb://localhost:27017/testdatabase', 16 | LOG_LEVEL: 'error', 17 | }, 18 | production: { 19 | PORT: process.env.PORT || 8080, 20 | MONGODB_URI: process.env.MONGODB_URI, 21 | LOG_LEVEL: 'warn', 22 | }, 23 | }; 24 | 25 | const currentEnvironment = process.env.NODE_ENV || 'development'; 26 | 27 | const config = environments[currentEnvironment]; 28 | 29 | if (!config) { 30 | throw new Error(`Environment configuration for "${currentEnvironment}" not found.`); 31 | } 32 | 33 | module.exports = config; 34 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # docker/Dockerfile 2 | 3 | # Stage 1: Build the application 4 | FROM node:16 AS builder 5 | 6 | # Set the working directory 7 | WORKDIR /app 8 | 9 | # Copy package.json and package-lock.json 10 | COPY package*.json ./ 11 | 12 | # Install dependencies 13 | RUN npm install --production 14 | 15 | # Copy the rest of the application code 16 | COPY . . 17 | 18 | # Build the application (if applicable) 19 | RUN npm run build 20 | 21 | # Stage 2: Create the production image 22 | FROM node:16 AS production 23 | 24 | # Set the working directory 25 | WORKDIR /app 26 | 27 | # Copy only the necessary files from the builder stage 28 | COPY --from=builder /app . 29 | 30 | # Expose the application port 31 | EXPOSE 8080 32 | 33 | # Start the application 34 | CMD ["node", "src/index.js"] # Adjust the entry point as necessary 35 | -------------------------------------------------------------------------------- /docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | # docker/docker-compose.yml 2 | 3 | version: '3.8' 4 | 5 | services: 6 | app: 7 | build: 8 | context: .. 9 | dockerfile: docker/Dockerfile 10 | ports: 11 | - "8080:8080" # Map host port 8080 to container port 8080 12 | environment: 13 | NODE_ENV: production 14 | MONGODB_URI: mongodb://mongo:27017/mydatabase # Use the MongoDB service 15 | depends_on: 16 | - mongo 17 | networks: 18 | - app-network 19 | 20 | mongo: 21 | image: mongo:latest 22 | ports: 23 | - "27017:27017" # Map host port 27017 to container port 27017 24 | volumes: 25 | - mongo-data:/data/db # Persist MongoDB data 26 | networks: 27 | - app-network 28 | 29 | networks: 30 | app-network: 31 | driver: bridge 32 | 33 | volumes: 34 | mongo-data: 35 | -------------------------------------------------------------------------------- /docs/PiEcosystemHub.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KOSASIH/PiEcosystemHub/0a40a18f471d29326048c4193e55135fec7a03a3/docs/PiEcosystemHub.jpeg -------------------------------------------------------------------------------- /docs/api_reference.md: -------------------------------------------------------------------------------- 1 | # API Documentation 2 | 3 | ## Introduction 4 | This document provides a reference for the API endpoints available in the Pi Ecosystem Integration Hub. 5 | 6 | ## Base URL 7 | 8 | [http://localhost:3000/api](http://localhost:3000/api) 9 | 10 | 11 | ## Authentication 12 | 13 | ### POST /auth/login 14 | - **Description**: Log in a user. 15 | - **Request Body**: 16 | ```json 17 | 1 { 18 | 2 "email": "user@example.com", 19 | 3 "password": "yourpassword" 20 | 4 } 21 | ``` 22 | 23 | - Response: 24 | - 200 OK: Returns user information and a token. 25 | - 401 Unauthorized: Invalid credentials. 26 | 27 | **POST** /auth/register 28 | - **Description**: Register a new user. 29 | - **Request Body**: 30 | 31 | ```json 32 | 1 { 33 | 2 "username": "newuser", 34 | 3 "email": "user@example.com", 35 | 4 "password": "yourpassword" 36 | 5 } 37 | ``` 38 | 39 | - Response: 40 | - 201 Created: Returns the created user information. 41 | - 400 Bad Request: Validation errors. 42 | 43 | ### dApp Management 44 | - **GET** /dapps 45 | - **Description**: Retrieve a list of all dApps. 46 | - **Response**: 47 | - 200 OK: Returns an array of dApp objects. 48 | 49 | ### POST /dapps 50 | - **Description**: Create a new dApp. 51 | - **Request Body**: 52 | 53 | ```json 54 | 1 { 55 | 2 "name": "My dApp", 56 | 3 "description": "Description of my dApp", 57 | 4 "url": "http://mydapp.com" 58 | 5 } 59 | 60 | - Response: 61 | - 201 Created: Returns the created dApp object. 62 | - 400 Bad Request: Validation errors. 63 | 64 | # Conclusion 65 | For more detailed information on each endpoint, including additional parameters and response formats, please refer to the source code or contact the development team. 66 | -------------------------------------------------------------------------------- /docs/architecture.md: -------------------------------------------------------------------------------- 1 | # System Architecture Overview 2 | 3 | ## Introduction 4 | The Pi Ecosystem Integration Hub (PEIH) is designed to facilitate the integration of decentralized applications (dApps) within the Pi Network. This document provides an overview of the system architecture, including its components and interactions. 5 | 6 | ## Architecture Diagram 7 | ![Architecture Diagram](PiEcosystemHub.jpeg) 8 | 9 | ## Components 10 | 11 | ### 1. Frontend 12 | - **Technology Stack**: React.js, Redux, CSS 13 | - **Responsibilities**: 14 | - User interface for interacting with dApps 15 | - User authentication and management 16 | - Displaying dApp marketplace 17 | 18 | ### 2. Backend 19 | - **Technology Stack**: Node.js, Express.js, MongoDB 20 | - **Responsibilities**: 21 | - API endpoints for user and dApp management 22 | - Business logic for handling transactions 23 | - Database interactions 24 | 25 | ### 3. Database 26 | - **Database Type**: MongoDB 27 | - **Responsibilities**: 28 | - Storing user data, dApp information, and transaction records 29 | 30 | ### 4. Middleware 31 | - **Responsibilities**: 32 | - Authentication and authorization 33 | - Error handling 34 | - Logging 35 | 36 | ## Communication 37 | - **Frontend to Backend**: RESTful API calls 38 | - **Database to Backend**: Mongoose ODM for MongoDB 39 | 40 | ## Conclusion 41 | This architecture is designed to be scalable and modular, allowing for easy integration of new features and dApps in the future. 42 | -------------------------------------------------------------------------------- /docs/developer_guide.md: -------------------------------------------------------------------------------- 1 | # Developer Guide 2 | 3 | ## Introduction 4 | This guide is intended for developers who wish to contribute to the Pi Ecosystem Integration Hub. It covers the necessary steps to set up your development environment and start building. 5 | 6 | ## Setting Up Your Environment 7 | 8 | ### Node.js and npm 9 | - Install Node.js (version 14 or higher) from the official website. 10 | - Verify your installation by running `node -v` and `npm -v` in your terminal. 11 | 12 | ### Clone the Repository 13 | - Clone the repository using `git clone https://github.com/KOSASIH/PiEcosystemHub.git`. 14 | - Navigate to the cloned repository using `cd PiEcosystemHub`. 15 | 16 | ### Install Dependencies 17 | - Run `npm install` to install the required dependencies. 18 | 19 | ### Start the Application 20 | - Run `npm start` to start the application. 21 | 22 | ## Contributing to the Codebase 23 | 24 | ### Creating a New Branch 25 | - Run `git checkout -b feature/YourFeatureName` to create a new branch. 26 | 27 | ### Writing Code 28 | - Implement your feature or fix. 29 | - Follow the existing coding style and conventions. 30 | 31 | ### Committing Changes 32 | - Run `git commit -m "Add your message here"` to commit your changes. 33 | 34 | ### Pushing to Your Fork 35 | - Run `git push origin feature/YourFeatureName` to push your changes to your fork. 36 | 37 | ### Creating a Pull Request 38 | - Go to the original repository and click on "New Pull Request". 39 | 40 | ## Conclusion 41 | For more information on contributing to the project, please refer to [CONTRIBUTING.md](CONTRIBUTING.md). 42 | -------------------------------------------------------------------------------- /docs/user_guide.md: -------------------------------------------------------------------------------- 1 | # User Guide 2 | 3 | ## Introduction 4 | Welcome to the Pi Ecosystem Integration Hub! This guide will help you navigate the platform and utilize its features effectively. 5 | 6 | ## Getting Started 7 | 8 | ### Creating an Account 9 | 1. Visit the [registration page](http://localhost:3000/register). 10 | 2. Fill in your details (username, email, password). 11 | 3. Click "Register" to create your account. 12 | 13 | ### Logging In 14 | 1. Go to the [login page](http://localhost:3000/login). 15 | 2. Enter your email and password. 16 | 3. Click "Login" to access your dashboard. 17 | 18 | ## Using the dApp Marketplace 19 | 20 | ### Browsing dApps 21 | - Navigate to the "Marketplace" section from the main menu. 22 | - Browse through the list of available dApps. 23 | 24 | ### Interacting with dApps 25 | - Click on a dApp to view its details. 26 | - Follow the instructions provided by the dApp to interact with it. 27 | 28 | ## Managing Your Profile 29 | - Access your profile settings from the top-right corner. 30 | - Update your information and preferences as needed. 31 | 32 | ## Conclusion 33 | For further assistance, please refer to the [FAQ](link-to-faq) or contact our support team. 34 | -------------------------------------------------------------------------------- /scripts/deploy.js: -------------------------------------------------------------------------------- 1 | // scripts/deploy.js 2 | 3 | const { exec } = require('child_process'); 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | require('dotenv').config(); 7 | 8 | const DEPLOY_DIR = path.join(__dirname, '../build'); // Adjust as necessary 9 | 10 | const deploy = () => { 11 | console.log('Starting deployment...'); 12 | 13 | // Build the application 14 | exec('npm run build', (error, stdout, stderr) => { 15 | if (error) { 16 | console.error(`Error during build: ${error.message}`); 17 | return; 18 | } 19 | if (stderr) { 20 | console.error(`Build stderr: ${stderr}`); 21 | return; 22 | } 23 | console.log(`Build output: ${stdout}`); 24 | 25 | // Deploy to the server (this is a placeholder command) 26 | exec(`scp -r ${DEPLOY_DIR}/* ${process.env.REMOTE_USER}@${process.env.REMOTE_HOST}:${process.env.REMOTE_PATH}`, (error, stdout, stderr) => { 27 | if (error) { 28 | console.error(`Error during deployment: ${error.message}`); 29 | return; 30 | } 31 | if (stderr) { 32 | console.error(`Deployment stderr: ${stderr}`); 33 | return; 34 | } 35 | console.log(`Deployment output: ${stdout}`); 36 | console.log('Deployment completed successfully!'); 37 | }); 38 | }); 39 | }; 40 | 41 | deploy(); 42 | -------------------------------------------------------------------------------- /scripts/seedDatabase.js: -------------------------------------------------------------------------------- 1 | // scripts/seedDatabase.js 2 | 3 | const mongoose = require('mongoose'); 4 | const dotenv = require('dotenv'); 5 | const User = require('../models/User'); // Adjust the path to your User model 6 | const DApp = require('../models/DApp'); // Adjust the path to your DApp model 7 | 8 | dotenv.config(); 9 | 10 | const seedDatabase = async () => { 11 | try { 12 | // Connect to the database 13 | await mongoose.connect(process.env.MONGODB_URI, { 14 | useNewUrlParser: true, 15 | useUnifiedTopology: true, 16 | }); 17 | console.log('Connected to the database.'); 18 | 19 | // Clear existing data 20 | await User.deleteMany({}); 21 | await DApp.deleteMany({}); 22 | console.log('Cleared existing data.'); 23 | 24 | // Seed new data 25 | const users = await User.insertMany([ 26 | { username: 'admin', email: 'admin@example.com', password: 'Password123!' }, 27 | { username: 'user1', email: 'user1@example.com', password: 'Password123!' }, 28 | ]); 29 | console.log('Seeded users:', users); 30 | 31 | const dApps = await DApp.insertMany([ 32 | { name: 'DApp 1', description: 'Description for DApp 1', url: 'http://dapp1.com', createdBy: users[0]._id }, 33 | { name: 'DApp 2', description: 'Description for DApp 2', url: 'http://dapp2.com', createdBy: users[1]._id }, 34 | ]); 35 | console.log('Seeded dApps:', dApps); 36 | 37 | } catch (error) { 38 | console.error('Error seeding database:', error); 39 | } finally { 40 | // Close the database connection 41 | await mongoose.connection.close(); 42 | console.log('Database connection closed.'); 43 | } 44 | }; 45 | 46 | seedDatabase(); 47 | -------------------------------------------------------------------------------- /src/blockchain/pi-connector.js: -------------------------------------------------------------------------------- 1 | /** 2 | * pi-connector.js 3 | * 4 | * The most super advanced, ultra high-tech, feature-rich, powerful, unstoppable, 5 | * unmatched Pi Network blockchain connector module. 6 | * 7 | * Features: 8 | * - Connects securely and efficiently to Pi Network blockchain nodes 9 | * - Supports multiple endpoints for redundancy and failover 10 | * - Automatic reconnection and exponential backoff retry logic 11 | * - Async operations with timeout and error handling 12 | * - Event-driven architecture for monitoring connection status and errors 13 | * - Batch request support for optimized blockchain queries 14 | * - Secure signing and verification placeholder for future extensions 15 | * - Highly configurable with environment variables and runtime options 16 | */ 17 | 18 | const EventEmitter = require('events'); 19 | const axios = require('axios'); 20 | 21 | class PiConnector extends EventEmitter { 22 | /** 23 | * Create a PiConnector instance. 24 | * @param {Array} endpoints - List of Pi Network node endpoints for connection redundancy. 25 | * @param {number} [timeout=10000] - HTTP request timeout in milliseconds. 26 | * @param {number} [maxRetries=5] - Maximum number of retries for failed requests. 27 | * @param {number} [retryDelay=2000] - Initial retry delay in milliseconds for exponential backoff. 28 | */ 29 | constructor({ 30 | endpoints = ['https://node1.pi.network', 'https://node2.pi.network'], 31 | timeout = 10000, 32 | maxRetries = 5, 33 | retryDelay = 2000, 34 | } = {}) { 35 | super(); 36 | if (!Array.isArray(endpoints) || endpoints.length === 0) { 37 | throw new Error('At least one endpoint must be provided'); 38 | } 39 | this.endpoints = endpoints; 40 | this.timeout = timeout; 41 | this.maxRetries = maxRetries; 42 | this.retryDelay = retryDelay; 43 | this.currentEndpointIndex = 0; 44 | this.isConnected = false; 45 | 46 | this._log('PiConnector initialized'); 47 | } 48 | 49 | _log(message) { 50 | this.emit('log', `[PiConnector] ${message}`); 51 | } 52 | 53 | _sleep(ms) { 54 | return new Promise(resolve => setTimeout(resolve, ms)); 55 | } 56 | 57 | /** 58 | * Get the current endpoint URL. 59 | * @returns {string} 60 | */ 61 | get currentEndpoint() { 62 | return this.endpoints[this.currentEndpointIndex]; 63 | } 64 | 65 | /** 66 | * Rotate to the next endpoint for failover. 67 | */ 68 | _rotateEndpoint() { 69 | this.currentEndpointIndex = (this.currentEndpointIndex + 1) % this.endpoints.length; 70 | this._log(`Rotated endpoint to ${this.currentEndpoint}`); 71 | } 72 | 73 | /** 74 | * Make a POST JSON-RPC call to the Pi Network blockchain node with retries and failover. 75 | * @param {string} method - The RPC method name. 76 | * @param {Array|Object} params - The parameters for the RPC call. 77 | * @returns {Promise} 78 | */ 79 | async rpcCall(method, params = []) { 80 | let lastError = null; 81 | for (let attempt = 1; attempt <= this.maxRetries; attempt++) { 82 | const endpoint = this.currentEndpoint; 83 | try { 84 | this._log(`RPC call attempt ${attempt}: method=${method}, endpoint=${endpoint}`); 85 | 86 | const payload = { 87 | jsonrpc: '2.0', 88 | id: Date.now(), 89 | method, 90 | params, 91 | }; 92 | 93 | const response = await axios.post(endpoint, payload, { timeout: this.timeout }); 94 | 95 | if (response.status === 200 && response.data) { 96 | if (response.data.error) { 97 | this._log(`RPC error response: ${JSON.stringify(response.data.error)}`); 98 | throw new Error(`RPC Error: ${response.data.error.message || 'Unknown error'}`); 99 | } 100 | this._log(`RPC call successful: method=${method}`); 101 | this.isConnected = true; 102 | this.emit('connected', endpoint); 103 | return response.data.result; 104 | } else { 105 | throw new Error(`Unexpected status code ${response.status}`); 106 | } 107 | } catch (error) { 108 | lastError = error; 109 | this._log(`RPC call failed on endpoint ${endpoint}: ${error.message}`); 110 | this.emit('error', { endpoint, error }); 111 | 112 | this._rotateEndpoint(); 113 | 114 | // Exponential backoff delay before retry 115 | const delay = this.retryDelay * Math.pow(2, attempt - 1); 116 | this._log(`Waiting ${delay}ms before retrying...`); 117 | await this._sleep(delay); 118 | } 119 | } 120 | this.isConnected = false; 121 | this.emit('disconnected', this.currentEndpoint); 122 | throw new Error(`Failed RPC call after ${this.maxRetries} attempts: ${lastError.message || lastError}`); 123 | } 124 | 125 | /** 126 | * Batch multiple RPC calls for efficient querying. 127 | * @param {Array<{ method: string, params: Array|Object }>} calls 128 | * @returns {Promise>} 129 | */ 130 | async batchRpcCall(calls) { 131 | if (!Array.isArray(calls) || calls.length === 0) { 132 | throw new Error('Batch RPC calls must be a non-empty array'); 133 | } 134 | const payload = calls.map((call, idx) => ({ 135 | jsonrpc: '2.0', 136 | id: Date.now() + idx, 137 | method: call.method, 138 | params: call.params, 139 | })); 140 | 141 | let lastError = null; 142 | for (let attempt = 1; attempt <= this.maxRetries; attempt++) { 143 | const endpoint = this.currentEndpoint; 144 | try { 145 | this._log(`Batch RPC call attempt ${attempt}, endpoint=${endpoint}`); 146 | 147 | const response = await axios.post(endpoint, payload, { timeout: this.timeout }); 148 | 149 | if (response.status === 200 && Array.isArray(response.data)) { 150 | this._log('Batch RPC call successful'); 151 | this.isConnected = true; 152 | this.emit('connected', endpoint); 153 | return response.data.map(item => { 154 | if (item.error) { 155 | return { error: item.error }; 156 | } 157 | return item.result; 158 | }); 159 | } else { 160 | throw new Error(`Unexpected response format or status ${response.status}`); 161 | } 162 | } catch (error) { 163 | lastError = error; 164 | this._log(`Batch RPC call failed on endpoint ${endpoint}: ${error.message}`); 165 | this.emit('error', { endpoint, error }); 166 | 167 | this._rotateEndpoint(); 168 | 169 | const delay = this.retryDelay * Math.pow(2, attempt - 1); 170 | this._log(`Waiting ${delay}ms before retrying batch call...`); 171 | await this._sleep(delay); 172 | } 173 | } 174 | this.isConnected = false; 175 | this.emit('disconnected', this.currentEndpoint); 176 | throw new Error(`Failed batch RPC call after ${this.maxRetries} attempts: ${lastError.message || lastError}`); 177 | } 178 | 179 | /** 180 | * Placeholder for signing messages or transactions (to be implemented) 181 | * @param {string|Buffer} message 182 | * @returns {Promise} signature in hex format 183 | */ 184 | async signMessage(message) { 185 | // Implement secure signing logic here for transactions or messages 186 | // Examples: hardware wallet integration, private key management, or external signers 187 | this._log('signMessage placeholder called - implement secure signing'); 188 | throw new Error('signMessage method is not implemented'); 189 | } 190 | 191 | /** 192 | * Placeholder for verifying message signatures (to be implemented) 193 | * @param {string|Buffer} message 194 | * @param {string} signature - hex string 195 | * @param {string} publicKey 196 | * @returns {Promise} 197 | */ 198 | async verifySignature(message, signature, publicKey) { 199 | // Implement signature verification logic 200 | this._log('verifySignature placeholder called - implement verification'); 201 | throw new Error('verifySignature method is not implemented'); 202 | } 203 | } 204 | 205 | module.exports = PiConnector; 206 | 207 | /** 208 | * Example usage: 209 | * 210 | * const PiConnector = require('./pi-connector'); 211 | * const connector = new PiConnector({ 212 | * endpoints: ['https://node1.pi.network', 'https://node2.pi.network'], 213 | * timeout: 8000, 214 | * maxRetries: 3, 215 | * retryDelay: 1500, 216 | * }); 217 | * 218 | * connector.on('log', console.log); 219 | * connector.on('error', ({endpoint, error}) => { 220 | * console.error(`Error on endpoint ${endpoint}:`, error.message); 221 | * }); 222 | * connector.on('connected', endpoint => console.log('Connected to endpoint:', endpoint)); 223 | * connector.on('disconnected', endpoint => console.warn('Disconnected from endpoint:', endpoint)); 224 | * 225 | * async function test() { 226 | * try { 227 | * const blockNumber = await connector.rpcCall('eth_blockNumber', []); 228 | * console.log('Current block number:', blockNumber); 229 | * } catch (err) { 230 | * console.error('RPC call error:', err); 231 | * } 232 | * } 233 | * 234 | * test(); 235 | */ 236 | -------------------------------------------------------------------------------- /src/components/Card.css: -------------------------------------------------------------------------------- 1 | /* src/components/Card.css */ 2 | 3 | .card { 4 | border: 1px solid #ccc; 5 | border-radius: 8px; 6 | padding: 20px; 7 | margin: 10px; 8 | text-align: center; 9 | transition: transform 0.2s; 10 | } 11 | 12 | .card:hover { 13 | transform: scale(1.05); 14 | } 15 | 16 | .card-button { 17 | background-color: #007bff; 18 | color: white; 19 | padding: 10px 15px; 20 | text-decoration: none; 21 | border-radius: 5px; 22 | transition: background-color 0.3s; 23 | } 24 | 25 | .card-button:hover { 26 | background-color: #0056b3; 27 | } 28 | -------------------------------------------------------------------------------- /src/components/Card.js: -------------------------------------------------------------------------------- 1 | // src/components/Card.js 2 | 3 | import React from 'react'; 4 | import PropTypes from 'prop-types'; 5 | import './Card.css'; // Import CSS for styling 6 | 7 | const Card = ({ dApp }) => { 8 | return ( 9 |
10 |

{dApp.name}

11 |

{dApp.description}

12 | Visit dApp 13 |
14 | ); 15 | }; 16 | 17 | Card.propTypes = { 18 | dApp: PropTypes.shape({ 19 | name: PropTypes.string.isRequired, 20 | description: PropTypes.string.isRequired, 21 | url: PropTypes.string.isRequired, 22 | }).isRequired, 23 | }; 24 | 25 | export default Card; 26 | -------------------------------------------------------------------------------- /src/components/Footer.css: -------------------------------------------------------------------------------- 1 | /* src/components/Footer.css */ 2 | 3 | .footer { 4 | background-color: #282c34; 5 | color: white; 6 | text-align: center; 7 | padding: 10px 0; 8 | position: relative; 9 | bottom: 0; 10 | width: 100%; 11 | } 12 | 13 | .footer ul { 14 | list-style: none; 15 | padding: 0; 16 | } 17 | 18 | .footer ul li { 19 | display: inline; 20 | margin: 0 10px; 21 | } 22 | 23 | .footer ul li a { 24 | color: white; 25 | text-decoration: none; 26 | } 27 | -------------------------------------------------------------------------------- /src/components/Footer.js: -------------------------------------------------------------------------------- 1 | // src/components/Footer.js 2 | 3 | import React from 'react'; 4 | import './Footer.css'; // Import CSS for styling 5 | 6 | const Footer = () => { 7 | return ( 8 | 15 | ); 16 | }; 17 | 18 | export default Footer; 19 | -------------------------------------------------------------------------------- /src/components/Header.css: -------------------------------------------------------------------------------- 1 | /* src/components/Header.css */ 2 | 3 | .header { 4 | background-color: #282c34; 5 | padding: 20px; 6 | color: white; 7 | text-align: center; 8 | } 9 | 10 | .header nav ul { 11 | list-style: none; 12 | padding: 0; 13 | } 14 | 15 | .header nav ul li { 16 | display: inline; 17 | margin: 0 15px; 18 | } 19 | 20 | .header nav ul li a { 21 | color: white; 22 | text-decoration: none; 23 | } 24 | -------------------------------------------------------------------------------- /src/components/Header.js: -------------------------------------------------------------------------------- 1 | // src/components/Header.js 2 | 3 | import React from 'react'; 4 | import { Link } from 'react-router-dom'; 5 | import PropTypes from 'prop-types'; 6 | import './Header.css'; // Import CSS for styling 7 | 8 | const Header = ({ title }) => { 9 | return ( 10 |
11 |

{title}

12 | 21 |
22 | ); 23 | }; 24 | 25 | Header.propTypes = { 26 | title: PropTypes.string.isRequired, 27 | }; 28 | 29 | export default Header; 30 | -------------------------------------------------------------------------------- /src/config/constants.py: -------------------------------------------------------------------------------- 1 | # src/constants.py 2 | 3 | """ 4 | PiEcosystemHub Configuration Constants 5 | This module contains constants related to the PiEcosystemHub, a platform for integrating decentralized applications (dApps) within the Pi Network. 6 | """ 7 | 8 | # General Configuration 9 | PI_ECOSYSTEM_HUB_VERSION = "1.0.0" # Current version of the PiEcosystemHub application 10 | PI_ECOSYSTEM_HUB_RELEASE_DATE = "2025-01-10" # Release date of the current version 11 | PI_ECOSYSTEM_HUB_NAME = "PiEcosystemHub" # Name of the application 12 | PI_ECOSYSTEM_HUB_DESCRIPTION = "A comprehensive platform for integrating decentralized applications (dApps) within the Pi Network." # Description of the application 13 | 14 | # Pi Coin Configuration 15 | PI_COIN_SYMBOL = "PI" # Symbol for Pi Coin 16 | PI_COIN_VALUE = 314159.00 # Fixed value of Pi Coin in USD 17 | PI_COIN_SUPPLY = 100_000_000_000 # Total supply of Pi Coin 18 | PI_COIN_DYNAMIC_SUPPLY = False # Disable dynamic supply adjustments for stability 19 | 20 | # Stablecoin Mechanisms 21 | PI_COIN_IS_STABLECOIN = True # Indicates that Pi Coin is a stablecoin 22 | PI_COIN_STABILITY_MECHANISM = "Collateralized" # Mechanism for maintaining stability 23 | PI_COIN_COLLATERAL_RATIO = 1.5 # Collateralization ratio (1.5 means $1.50 in collateral for every $1 of Pi Coin) 24 | PI_COIN_RESERVE_ASSETS = ["USD", "BTC", "ETH"] # List of assets backing the stablecoin 25 | 26 | # Transaction Fees 27 | PI_COIN_TRANSACTION_FEE = 0.005 # Transaction fee in USD 28 | PI_COIN_TRANSACTION_FEE_ADJUSTMENT = 0.0005 # Dynamic adjustment factor for transaction fees 29 | 30 | # Block Configuration 31 | PI_COIN_BLOCK_TIME = 5 # Average block time in seconds for faster transactions 32 | PI_COIN_BLOCK_TIME_ADJUSTMENT = 0.5 # Adjustment factor for block time based on network load 33 | 34 | # Mining Configuration 35 | PI_COIN_MINING_DIFFICULTY = 500 # Reduced difficulty for increased mining participation 36 | PI_COIN_MINING_DIFFICULTY_ADJUSTMENT = 0.05 # Adjustment factor for mining difficulty 37 | PI_COIN_MINING_REWARD = 25 # Increased reward for mining a block 38 | PI_COIN_MINING_REWARD_ADJUSTMENT = 1.0 # Dynamic adjustment for mining rewards 39 | 40 | # Network Protocol 41 | PI_COIN_NETWORK_PROTOCOL = "PoS" # Proof of Stake for energy efficiency 42 | PI_COIN_NETWORK_PROTOCOL_VERSION = "2.0.0" # Updated version of the network protocol 43 | 44 | # Transaction Configuration 45 | PI_COIN_MAX_TRANSACTION_SIZE = 2_000_000 # Increased maximum transaction size in bytes 46 | PI_COIN_DECIMALS = 18 # Number of decimal places for Pi Coin 47 | 48 | # Genesis Block Configuration 49 | PI_COIN_GENESIS_BLOCK_TIMESTAMP = "2025-01-01T00:00:00Z" # Timestamp of the genesis block 50 | 51 | # Governance Model 52 | PI_COIN_GOVERNANCE_MODEL = "Decentralized" # Governance model for Pi Coin 53 | PI_COIN_GOVERNANCE_VOTING_PERIOD = 1_209_600 # Voting period in seconds, 2 weeks 54 | 55 | # Security Features 56 | PI_COIN_ENCRYPTION_ALGORITHM = "AES-512" # Enhanced encryption algorithm for securing transactions 57 | PI_COIN_HASHING_ALGORITHM = "SHA-3" # Advanced hashing algorithm for block verification 58 | PI_COIN_SIGNATURE_SCHEME = "EdDSA" # More secure digital signature scheme for transaction signing 59 | PI_COIN_SECURITY_AUDIT_INTERVAL = 43200 # Security audit interval in seconds, 12 hours 60 | 61 | # Network Parameters 62 | PI_COIN_MAX_PEERS = 500 # Increased maximum number of peers in the network 63 | PI_COIN_NODE_TIMEOUT = 15 # Reduced timeout for node responses in seconds 64 | PI_COIN_CONNECTION_RETRY_INTERVAL = 2 # Reduced retry interval for node connections in seconds 65 | 66 | # Staking Parameters 67 | PI_COIN_STAKING_REWARD = 0.1 # Reward for staking Pi Coins 68 | PI_COIN_MINIMUM_STAKE = 100 # Minimum amount required to stake 69 | PI_COIN_STAKING_PERIOD = 604800 # Staking period in seconds, 1 week 70 | PI_COIN_STAKING_REWARD_ADJUSTMENT = 0.01 # Dynamic adjustment for staking rewards 71 | 72 | # Advanced # Advanced Features 73 | PI_COIN_ADVANCED_FEATURES_ENABLED = True # Flag to enable advanced features 74 | PI_COIN_FEATURES_LIST = ["Smart Contracts", "Decentralized Governance", "Cross-Chain Interoperability"] # List of advanced features available 75 | 76 | # Community Engagement 77 | PI_COIN_COMMUNITY_VOTING_THRESHOLD = 0.05 # Minimum percentage of votes required for community proposals to pass 78 | PI_COIN_COMMUNITY_PROPOSAL_DURATION = 604800 # Duration for community proposals in seconds, 1 week 79 | 80 | # API Configuration 81 | PI_COIN_API_BASE_URL = "https://api.piecosystemhub.com" # Base URL for the API 82 | PI_COIN_API_TIMEOUT = 10 # Timeout for API requests in seconds 83 | 84 | # Logging Configuration 85 | PI_COIN_LOGGING_LEVEL = "DEBUG" # Logging level for the application 86 | PI_COIN_LOGGING_FILE = "piecosystemhub.log" # Log file name 87 | 88 | # User Interface Configuration 89 | PI_COIN_UI_THEME = "dark" # Default theme for the user interface 90 | PI_COIN_UI_LANGUAGE = "en" # Default language for the user interface 91 | 92 | # End of constants.py 93 | -------------------------------------------------------------------------------- /src/controllers/ProductController.js: -------------------------------------------------------------------------------- 1 | // src/controllers/ProductController.js 2 | 3 | const Product = require('../models/Product'); 4 | const pricingService = require('../services/PricingService'); 5 | const logger = require('../utils/logger'); // Assuming you have a logger utility 6 | const { validateProduct } = require('../validators/productValidator'); // Assuming you have a validation utility 7 | 8 | class ProductController { 9 | constructor(productModel) { 10 | this.productModel = productModel; // Use a database model for production 11 | } 12 | 13 | // Create a new product 14 | async createProduct(req, res) { 15 | try { 16 | const { error } = validateProduct(req.body); 17 | if (error) { 18 | return res.status(400).json({ error: error.details[0].message }); 19 | } 20 | 21 | const { name, basePrice, description, category } = req.body; 22 | const newProduct = new this.productModel({ name, basePrice, description, category }); 23 | await newProduct.save(); // Save to the database 24 | logger.info(`Product created: ${newProduct.id}`); 25 | res.status(201).json(newProduct.getProductSummary()); 26 | } catch (error) { 27 | logger.error('Error creating product:', error.message); 28 | res.status(500).json({ error: 'Internal server error' }); 29 | } 30 | } 31 | 32 | // Get all products 33 | async getAllProducts(req, res) { 34 | try { 35 | const products = await this.productModel.find(); // Fetch from the database 36 | const productSummaries = products.map(product => product.getProductSummary()); 37 | res.status(200).json(productSummaries); 38 | } catch (error) { 39 | logger.error('Error fetching products:', error.message); 40 | res.status(500).json({ error: 'Internal server error' }); 41 | } 42 | } 43 | 44 | // Get a product by ID 45 | async getProductById(req, res) { 46 | const { id } = req.params; 47 | try { 48 | const product = await this.productModel.findById(id); // Fetch from the database 49 | if (product) { 50 | res.status(200).json(product.getProductSummary()); 51 | } else { 52 | res.status(404).json({ error: 'Product not found' }); 53 | } 54 | } catch (error) { 55 | logger.error('Error fetching product:', error.message); 56 | res.status(500).json({ error: 'Internal server error' }); 57 | } 58 | } 59 | 60 | // Update a product by ID 61 | async updateProduct(req, res) { 62 | const { id } = req.params; 63 | try { 64 | const product = await this.productModel.findById(id); // Fetch from the database 65 | if (!product) { 66 | return res.status(404).json({ error: 'Product not found' }); 67 | } 68 | 69 | const { error } = validateProduct(req.body); 70 | if (error) { 71 | return res.status(400).json({ error: error.details[0].message }); 72 | } 73 | 74 | product.updateProductDetails(req.body); 75 | await product.save(); // Save updated product to the database 76 | logger.info(`Product updated: ${product.id}`); 77 | res.status(200).json(product.getProductSummary()); 78 | } catch (error) { 79 | logger.error('Error updating product:', error.message); 80 | res.status(500).json({ error: 'Internal server error' }); 81 | } 82 | } 83 | 84 | // Delete a product by ID 85 | async deleteProduct(req, res) { 86 | const { id } = req.params; 87 | try { 88 | const product = await this.productModel.findByIdAndDelete(id); // Delete from the database 89 | if (!product) { 90 | return res.status(404).json({ error: 'Product not found' }); 91 | } 92 | 93 | logger.info(`Product deleted: ${id}`); 94 | res.status(204).send(); // No content 95 | } catch (error) { 96 | logger.error('Error deleting product:', error.message); 97 | res.status(500).json({ error: 'Internal server error' }); 98 | } 99 | } 100 | 101 | // Get product price in specified currency 102 | async getProductPriceInCurrency(req, res) { 103 | const { id, currency } = req.params; 104 | try { 105 | const product = await this.productModel.findById(id); // Fetch from the database 106 | if (!product) { 107 | return res.status(404).json({ error: 'Product not found' }); 108 | } 109 | 110 | const priceInCurrency = pricingService.convertPriceToCurrency(product.basePrice, currency); 111 | if (priceInCurrency === null) { 112 | return res.status(400).json({ error: 'Currency conversion failed' }); 113 | } 114 | 115 | res.status(200).json({ priceInCurrency }); 116 | } catch (error) { 117 | logger.error('Error fetching product price in currency:', error.message); 118 | res.status(500).json({ error: 'Internal server error' }); 119 | } 120 | } 121 | } 122 | 123 | // Export an instance of ProductController 124 | const productController = new ProductController(Product); // Pass the Product model to the controller 125 | module.exports = productController; 126 | -------------------------------------------------------------------------------- /src/dapps/MyDapp/example-dapp.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/dapps/README.md: -------------------------------------------------------------------------------- 1 | # PiEcosystemHub - Decentralized Applications (dApps) 2 | 3 | ## Overview 4 | PiEcosystemHub is a platform designed to integrate various decentralized applications (dApps) within the Pi Network. It aims to enhance user engagement and promote interoperability among dApps, creating a vibrant ecosystem for developers and users alike. 5 | 6 | ## Features 7 | - **Integration of dApps**: Seamlessly connect multiple dApps within the Pi Network. 8 | - **User Engagement**: Foster community interaction and participation through various decentralized applications. 9 | - **Interoperability**: Enable dApps to communicate and work together effectively. 10 | 11 | ## Getting Started 12 | 1. **Clone the Repository** 13 | ```bash 14 | git clone https://github.com/KOSASIH/PiEcosystemHub.git 15 | ``` 16 | 17 | 2. **Navigate to the dApps Directory** 18 | ```bash 19 | cd PiEcosystemHub/src/dapps 20 | ``` 21 | 22 | 3. **Install Dependencies** 23 | Follow the installation instructions specific to each dApp. 24 | 25 | ## Contributing 26 | Contributions are welcome! Please fork the repository and submit a pull request with your enhancements or bug fixes. 27 | 28 | ## License 29 | This project is licensed under the MIT License. 30 | 31 | --- 32 | 33 | _Join us in building a decentralized future with PiEcosystemHub!_ 34 | ``` ```md 35 | # PiEcosystemHub - Decentralized Applications (dApps) 36 | 37 | ## Overview 38 | PiEcosystemHub is a platform designed to integrate various decentralized applications (dApps) within the Pi Network. It aims to enhance user engagement and promote interoperability among dApps, creating a vibrant ecosystem for developers and users alike. 39 | 40 | ## Features 41 | - **Integration of dApps**: Seamlessly connect multiple dApps within the Pi Network. 42 | - **User Engagement**: Foster community interaction and participation through various decentralized applications. 43 | - **Interoperability**: Enable dApps to communicate and work together effectively. 44 | 45 | ## Getting Started 46 | 1. **Clone the Repository** 47 | ```bash 48 | git clone https://github.com/KOSASIH/PiEcosystemHub.git 49 | ``` 50 | 51 | 2. **Navigate to the dApps Directory** 52 | ```bash 53 | cd PiEcosystemHub/src/dapps 54 | ``` 55 | 56 | 3. **Install Dependencies** 57 | Follow the installation instructions specific to each dApp. 58 | 59 | ## Contributing 60 | Contributions are welcome! Please fork the repository and submit a pull request with your enhancements or bug fixes. 61 | 62 | ## License 63 | This project is licensed under the MIT License. 64 | 65 | --- 66 | 67 | _Join us in building a decentralized future with PiEcosystemHub!_ 68 | -------------------------------------------------------------------------------- /src/main/app.js: -------------------------------------------------------------------------------- 1 | // src/main/app.js 2 | 3 | import express from 'express'; 4 | import bodyParser from 'body-parser'; 5 | import cors from 'cors'; 6 | import helmet from 'helmet'; 7 | import morgan from 'morgan'; 8 | import { createConnection } from 'typeorm'; // Assuming you're using TypeORM for database 9 | import authRoutes from './routes/authRoutes'; 10 | import dAppRoutes from './routes/dAppRoutes'; 11 | import { CustomExceptionFilter } from './filters/custom-exception.filter'; // Custom error handling 12 | import { Logger } from '@nestjs/common'; 13 | 14 | const app = express(); 15 | const logger = new Logger('App'); 16 | 17 | // Middleware setup 18 | app.use(helmet()); // Security headers 19 | app.use(cors()); // Enable CORS 20 | app.use(bodyParser.json()); // Parse JSON bodies 21 | app.use(morgan('combined')); // HTTP request logging 22 | 23 | // Database connection (example with TypeORM) 24 | createConnection() 25 | .then(() => { 26 | logger.log('Database connected successfully'); 27 | }) 28 | .catch((error) => { 29 | logger.error('Database connection failed', error); 30 | process.exit(1); // Exit the process if the database connection fails 31 | }); 32 | 33 | // Routes 34 | app.use('/api/auth', authRoutes); 35 | app.use('/api/dapp', dAppRoutes); 36 | 37 | // Error handling middleware 38 | app.use((err, req, res, next) => { 39 | logger.error('Unhandled error', err); 40 | res.status(err.status || 500).json({ 41 | message: err.message || 'Internal Server Error', 42 | }); 43 | }); 44 | 45 | // Start the server 46 | const PORT = process.env.PORT || 3000; 47 | app.listen(PORT, () => { 48 | logger.log(`Server is running on http://localhost:${PORT}`); 49 | }); 50 | -------------------------------------------------------------------------------- /src/main/config.js: -------------------------------------------------------------------------------- 1 | // src/main/config.js 2 | 3 | require('dotenv').config(); 4 | 5 | const config = { 6 | port: process.env.PORT || 3000, 7 | databaseUri: process.env.DATABASE_URI || 'mongodb://localhost:27017/piecosystemhub', 8 | jwtSecret: process.env.JWT_SECRET || 'your_jwt_secret', 9 | // Add other configuration settings as needed 10 | }; 11 | 12 | module.exports = config; 13 | -------------------------------------------------------------------------------- /src/main/controllers/authController.js: -------------------------------------------------------------------------------- 1 | // src/main/controllers/authController.js 2 | 3 | import { Controller, Post, Body, Res, HttpStatus, UseFilters, UseGuards } from '@nestjs/common'; 4 | import { Response } from 'express'; 5 | import { AuthService } from '../services/auth.service'; 6 | import { CreateUser Dto } from '../dto/create-user.dto'; 7 | import { LoginUser Dto } from '../dto/login-user.dto'; 8 | import { CustomExceptionFilter } from '../filters/custom-exception.filter'; 9 | import { Logger } from '@nestjs/common'; 10 | import { RateLimit } from 'express-rate-limit'; 11 | 12 | @Controller('auth') 13 | @UseFilters(CustomExceptionFilter) // Custom error handling 14 | export class AuthController { 15 | private readonly logger = new Logger(AuthController.name); 16 | 17 | constructor(private readonly authService: AuthService) {} 18 | 19 | // Rate limiting middleware for login attempts 20 | private rateLimiter = new RateLimit({ 21 | windowMs: 15 * 60 * 1000, // 15 minutes 22 | max: 5, // Limit each IP to 5 login attempts per windowMs 23 | message: 'Too many login attempts, please try again later.', 24 | }); 25 | 26 | @Post('register') 27 | async register(@Body() createUser Dto: CreateUser Dto, @Res() res: Response) { 28 | try { 29 | const user = await this.authService.register(createUser Dto); 30 | this.logger.log(`User registered: ${user.email}`); 31 | return res.status(HttpStatus.CREATED).json({ message: 'User registered successfully' }); 32 | } catch (error) { 33 | this.logger.error('Error registering user', error); 34 | return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ message: 'Internal Server Error' }); 35 | } 36 | } 37 | 38 | @Post('login') 39 | @UseGuards(this.rateLimiter) // Apply rate limiting 40 | async login(@Body() loginUser Dto: LoginUser Dto, @Res() res: Response) { 41 | try { 42 | const token = await this.authService.login(loginUser Dto); 43 | this.logger.log(`User logged in: ${loginUser Dto.email}`); 44 | return res.status(HttpStatus.OK).json({ token }); 45 | } catch (error) { 46 | this.logger.error('Error logging in', error); 47 | return res.status(HttpStatus.UNAUTHORIZED).json({ message: 'Invalid credentials' }); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/controllers/dAppController.js: -------------------------------------------------------------------------------- 1 | // src/main/controllers/dAppController.js 2 | 3 | import { Controller, Get, Post, Body, Res, HttpStatus, UseFilters, UseGuards } from '@nestjs/common'; 4 | import { Response } from 'express'; 5 | import { RateLimit } from 'express-rate-limit'; 6 | import * as helmet from 'helmet'; 7 | import { Logger } from '@nestjs/common'; 8 | import { Cache } from 'cache-manager'; 9 | import { Inject } from '@nestjs/common'; 10 | import { CustomExceptionFilter } from '../filters/custom-exception.filter'; 11 | 12 | @Controller('dapp') 13 | @UseFilters(CustomExceptionFilter) // Custom error handling 14 | export class dAppController { 15 | private readonly logger = new Logger(dAppController.name); 16 | 17 | constructor(@Inject('CACHE_MANAGER') private cacheManager: Cache) {} 18 | 19 | // Rate limiting middleware 20 | private rateLimiter = new RateLimit({ 21 | windowMs: 15 * 60 * 1000, // 15 minutes 22 | max: 100, // Limit each IP to 100 requests per windowMs 23 | message: 'Too many requests, please try again later.', 24 | }); 25 | 26 | @Get('data') 27 | @UseGuards(this.rateLimiter) // Apply rate limiting 28 | async getData(@Res() res: Response) { 29 | try { 30 | const cachedData = await this.cacheManager.get('dataKey'); 31 | if (cachedData) { 32 | this.logger.log('Serving from cache'); 33 | return res.status(HttpStatus.OK).json(cachedData); 34 | } 35 | 36 | // Simulate data fetching 37 | const data = await this.fetchDataFromSource(); 38 | await this.cacheManager.set('dataKey', data, { ttl: 3600 }); // Cache for 1 hour 39 | this.logger.log('Serving fresh data'); 40 | return res.status(HttpStatus.OK).json(data); 41 | } catch (error) { 42 | this.logger.error('Error fetching data', error); 43 | return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ message: 'Internal Server Error' }); 44 | } 45 | } 46 | 47 | @Post('submit') 48 | async submitData(@Body() body: any, @Res() res: Response) { 49 | // Input validation can be added here 50 | try { 51 | // Process the submitted data 52 | this.logger.log('Data submitted', body); 53 | return res.status(HttpStatus.CREATED).json({ message: 'Data submitted successfully' }); 54 | } catch (error) { 55 | this.logger.error('Error submitting data', error); 56 | return res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({ message: 'Internal Server Error' }); 57 | } 58 | } 59 | 60 | private async fetchDataFromSource() { 61 | // Simulate a data fetch operation 62 | return new Promise((resolve) => { 63 | setTimeout(() => { 64 | resolve({ message: 'This is the fetched data' }); 65 | }, 1000); 66 | }); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/index.js: -------------------------------------------------------------------------------- 1 | // src/main/index.js 2 | 3 | const app = require('./app'); 4 | const config = require('./config'); 5 | 6 | const PORT = config.port || 3000; 7 | 8 | app.listen(PORT, () => { 9 | console.log(`Server is running on http://localhost:${PORT}`); 10 | }); 11 | -------------------------------------------------------------------------------- /src/main/middleware/errorMiddleware.js: -------------------------------------------------------------------------------- 1 | // src/main/middleware/errorMiddleware.js 2 | 3 | const errorHandler = (err, req, res, next) => { 4 | console.error(err); 5 | res.status(500).json({ message: 'Internal Server Error' }); 6 | }; 7 | 8 | module.exports = errorHandler; 9 | -------------------------------------------------------------------------------- /src/main/models/User.js: -------------------------------------------------------------------------------- 1 | // src/main/models/User.js 2 | 3 | const mongoose = require('mongoose'); 4 | 5 | // Define the user schema 6 | const userSchema = new mongoose.Schema({ 7 | username: { 8 | type: String, 9 | required: true, 10 | trim: true, 11 | minlength: 3, 12 | maxlength: 30, 13 | }, 14 | email: { 15 | type: String, 16 | required: true, 17 | unique: true, 18 | trim: true, 19 | lowercase: true, 20 | validate: { 21 | validator: function(v) { 22 | return /^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$/.test(v); 23 | }, 24 | message: props => `${props.value} is not a valid email!` 25 | } 26 | }, 27 | password: { 28 | type: String, 29 | required: true, 30 | minlength: 6, 31 | }, 32 | createdAt: { 33 | type: Date, 34 | default: Date.now, 35 | }, 36 | }); 37 | 38 | // Method to compare password 39 | userSchema.methods.comparePassword = async function(candidatePassword) { 40 | const bcrypt = require('bcrypt'); 41 | return await bcrypt.compare(candidatePassword, this.password); 42 | }; 43 | 44 | // Export the User model 45 | module.exports = mongoose.model('User ', userSchema); 46 | -------------------------------------------------------------------------------- /src/main/routes/authRoutes.js: -------------------------------------------------------------------------------- 1 | // src/main/routes/authRoutes.js 2 | 3 | import { Router } from 'express'; 4 | import { AuthController } from '../controllers/authController'; 5 | import { validate } from '../middleware/validate.middleware'; 6 | import { CreateUser Dto } from '../dto/create-user.dto'; 7 | import { LoginUser Dto } from '../dto/login-user.dto'; 8 | import { Logger } from '@nestjs/common'; 9 | import { RateLimit } from 'express-rate-limit'; 10 | 11 | const router = Router(); 12 | const logger = new Logger('AuthRoutes'); 13 | 14 | // Rate limiting middleware for login attempts 15 | const loginRateLimiter = new RateLimit({ 16 | windowMs: 15 * 60 * 1000, // 15 minutes 17 | max: 5, // Limit each IP to 5 login attempts per windowMs 18 | message: 'Too many login attempts, please try again later.', 19 | }); 20 | 21 | // Middleware to log requests 22 | router.use((req, res, next) => { 23 | logger.log(`Request: ${req.method} ${req.originalUrl}`); 24 | next(); 25 | }); 26 | 27 | // Route for user registration 28 | router.post('/register', validate(CreateUser Dto), async (req, res) => { 29 | try { 30 | const user = await AuthController.register(req.body); 31 | logger.log(`User registered: ${user.email}`); 32 | return res.status(201).json({ message: 'User registered successfully' }); 33 | } catch (error) { 34 | logger.error('Error registering user', error); 35 | return res.status(500).json({ message: 'Internal Server Error' }); 36 | } 37 | }); 38 | 39 | // Route for user login 40 | router.post('/login', loginRateLimiter, validate(LoginUser Dto), async (req, res) => { 41 | try { 42 | const token = await AuthController.login(req.body); 43 | logger.log(`User logged in: ${req.body.email}`); 44 | return res.status(200).json({ token }); 45 | } catch (error) { 46 | logger.error('Error logging in', error); 47 | return res.status(401).json({ message: 'Invalid credentials' }); 48 | } 49 | }); 50 | 51 | export default router; 52 | -------------------------------------------------------------------------------- /src/main/routes/dAppRoutes.js: -------------------------------------------------------------------------------- 1 | // src/main/routes/dAppRoutes.js 2 | 3 | import { Router } from 'express'; 4 | import { dAppController } from '../controllers/dAppController'; 5 | import { validate } from '../middleware/validate.middleware'; 6 | import { CreateDataDto } from '../dto/create-data.dto'; 7 | import { AuthMiddleware } from '../middleware/auth.middleware'; 8 | import { Logger } from '@nestjs/common'; 9 | import { RateLimit } from 'express-rate-limit'; 10 | 11 | const router = Router(); 12 | const logger = new Logger('dAppRoutes'); 13 | 14 | // Rate limiting middleware for specific routes 15 | const rateLimiter = new RateLimit({ 16 | windowMs: 15 * 60 * 1000, // 15 minutes 17 | max: 100, // Limit each IP to 100 requests per windowMs 18 | message: 'Too many requests, please try again later.', 19 | }); 20 | 21 | // Middleware to log requests 22 | router.use((req, res, next) => { 23 | logger.log(`Request: ${req.method} ${req.originalUrl}`); 24 | next(); 25 | }); 26 | 27 | // Public route to get data 28 | router.get('/data', rateLimiter, dAppController.getData); 29 | 30 | // Protected route to submit data 31 | router.post('/submit', AuthMiddleware, validate(CreateDataDto), dAppController.submitData); 32 | 33 | export default router; 34 | -------------------------------------------------------------------------------- /src/middleware/authMiddleware.js: -------------------------------------------------------------------------------- 1 | // src/middleware/authMiddleware.js 2 | 3 | const jwt = require('jsonwebtoken'); 4 | const User = require('../models/User'); 5 | 6 | const authMiddleware = async (req, res, next) => { 7 | const token = req.headers['authorization']?.split(' ')[1]; // Extract token from Authorization header 8 | 9 | if (!token) { 10 | return res.status(401).json({ message: 'No token provided, authorization denied.' }); 11 | } 12 | 13 | try { 14 | const decoded = jwt.verify(token, process.env.JWT_SECRET); // Verify token 15 | req.user = await User.findById(decoded.id); // Attach user to request object 16 | if (!req.user) { 17 | return res.status(401).json({ message: 'Token is not valid.' }); 18 | } 19 | next(); // Proceed to the next middleware or route handler 20 | } catch (error) { 21 | return res.status(401).json({ message: 'Token is not valid.' }); 22 | } 23 | }; 24 | 25 | module.exports = authMiddleware; 26 | -------------------------------------------------------------------------------- /src/middleware/errorMiddleware.js: -------------------------------------------------------------------------------- 1 | // src/middleware/errorMiddleware.js 2 | 3 | const errorMiddleware = (err, req, res, next) => { 4 | console.error(err); // Log the error for debugging 5 | 6 | const statusCode = err.statusCode || 500; // Default to 500 if no status code is provided 7 | const message = err.message || 'Internal Server Error'; // Default message 8 | 9 | res.status(statusCode).json({ 10 | success: false, 11 | status: statusCode, 12 | message: message, 13 | stack: process.env.NODE_ENV === 'development' ? err.stack : undefined, // Show stack trace in development 14 | }); 15 | }; 16 | 17 | module.exports = errorMiddleware; 18 | -------------------------------------------------------------------------------- /src/models/Transaction.js: -------------------------------------------------------------------------------- 1 | // src/models/Transaction.js 2 | 3 | const mongoose = require('mongoose'); 4 | 5 | const transactionSchema = new mongoose.Schema({ 6 | user: { 7 | type: mongoose.Schema.Types.ObjectId, 8 | ref: 'User ', 9 | required: true, 10 | }, 11 | dApp: { 12 | type: mongoose.Schema.Types.ObjectId, 13 | ref: 'dApp', 14 | required: true, 15 | }, 16 | amount: { 17 | type: Number, 18 | required: true, 19 | min: 0, 20 | }, 21 | transactionDate: { 22 | type: Date, 23 | default: Date.now, 24 | }, 25 | status: { 26 | type: String, 27 | enum: ['pending', 'completed', 'failed'], 28 | default: 'pending', 29 | }, 30 | }); 31 | 32 | // Export the Transaction model 33 | module.exports = mongoose.model('Transaction', transactionSchema); 34 | -------------------------------------------------------------------------------- /src/models/User.js: -------------------------------------------------------------------------------- 1 | // src/models/User.js 2 | 3 | import mongoose from 'mongoose'; 4 | import bcrypt from 'bcrypt'; 5 | 6 | const userSchema = new mongoose.Schema({ 7 | username: { 8 | type: String, 9 | required: true, 10 | unique: true, 11 | trim: true, 12 | }, 13 | email: { 14 | type: String, 15 | required: true, 16 | unique: true, 17 | trim: true, 18 | lowercase: true, 19 | validate: { 20 | validator: function(v) { 21 | // Simple email validation 22 | return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v); 23 | }, 24 | message: props => `${props.value} is not a valid email!` 25 | }, 26 | }, 27 | password: { 28 | type: String, 29 | required: true, 30 | minlength: 6, 31 | }, 32 | createdAt: { 33 | type: Date, 34 | default: Date.now, 35 | }, 36 | updatedAt: { 37 | type: Date, 38 | default: Date.now, 39 | }, 40 | }); 41 | 42 | // Middleware to hash the password before saving 43 | userSchema.pre('save', async function(next) { 44 | if (this.isModified('password')) { 45 | this.password = await bcrypt.hash(this.password, 10); 46 | } 47 | this.updatedAt = Date.now(); 48 | next(); 49 | }); 50 | 51 | // Method to compare passwords 52 | userSchema.methods.comparePassword = async function(candidatePassword) { 53 | return await bcrypt.compare(candidatePassword, this.password); 54 | }; 55 | 56 | // Create the model 57 | const User = mongoose.model('User ', userSchema); 58 | 59 | export default User; 60 | -------------------------------------------------------------------------------- /src/models/dApp.js: -------------------------------------------------------------------------------- 1 | // src/models/dApp.js 2 | 3 | import mongoose from 'mongoose'; 4 | 5 | const dAppSchema = new mongoose.Schema({ 6 | name: { 7 | type: String, 8 | required: true, 9 | trim: true, 10 | }, 11 | description: { 12 | type: String, 13 | required: true, 14 | trim: true, 15 | }, 16 | url: { 17 | type: String, 18 | required: true, 19 | validate: { 20 | validator: function(v) { 21 | // Simple URL validation 22 | return /^(ftp|http|https):\/\/[^ "]+$/.test(v); 23 | }, 24 | message: props => `${props.value} is not a valid URL!` 25 | }, 26 | }, 27 | createdAt: { 28 | type: Date, 29 | default: Date.now, 30 | }, 31 | updatedAt: { 32 | type: Date, 33 | default: Date.now, 34 | }, 35 | }); 36 | 37 | // Middleware to update the updatedAt field before saving 38 | dAppSchema.pre('save', function(next) { 39 | this.updatedAt = Date.now(); 40 | next(); 41 | }); 42 | 43 | // Create the model 44 | const dApp = mongoose.model('dApp', dAppSchema); 45 | 46 | export default dApp; 47 | -------------------------------------------------------------------------------- /src/services/apiService.js: -------------------------------------------------------------------------------- 1 | // src/services/apiService.js 2 | 3 | import axios from 'axios'; 4 | import { Logger } from '@nestjs/common'; 5 | 6 | const logger = new Logger('ApiService'); 7 | 8 | class ApiService { 9 | constructor(baseURL) { 10 | this.apiClient = axios.create({ 11 | baseURL, 12 | timeout: 10000, // Set a timeout for requests 13 | headers: { 14 | 'Content-Type': 'application/json', 15 | }, 16 | }); 17 | 18 | // Interceptors for request and response 19 | this.apiClient.interceptors.request.use( 20 | (config) => { 21 | // You can add authorization tokens or other headers here 22 | logger.log(`Request: ${config.method.toUpperCase()} ${config.url}`); 23 | return config; 24 | }, 25 | (error) => { 26 | logger.error('Request error', error); 27 | return Promise.reject(error); 28 | } 29 | ); 30 | 31 | this.apiClient.interceptors.response.use( 32 | (response) => { 33 | logger.log(`Response: ${response.status} ${response.config.url}`); 34 | return response.data; // Return only the data part of the response 35 | }, 36 | (error) => { 37 | logger.error('Response error', error); 38 | // Handle specific error responses 39 | if (error.response) { 40 | return Promise.reject({ 41 | status: error.response.status, 42 | message: error.response.data.message || 'An error occurred', 43 | }); 44 | } 45 | return Promise.reject({ 46 | status: 500, 47 | message: 'Network Error', 48 | }); 49 | } 50 | ); 51 | } 52 | 53 | async get(endpoint, params = {}) { 54 | try { 55 | const response = await this.apiClient.get(endpoint, { params }); 56 | return response; 57 | } catch (error) { 58 | throw error; // Rethrow the error for handling in the calling function 59 | } 60 | } 61 | 62 | async post(endpoint, data) { 63 | try { 64 | const response = await this.apiClient.post(endpoint, data); 65 | return response; 66 | } catch (error) { 67 | throw error; // Rethrow the error for handling in the calling function 68 | } 69 | } 70 | 71 | async put(endpoint, data) { 72 | try { 73 | const response = await this.apiClient.put(endpoint, data); 74 | return response; 75 | } catch (error) { 76 | throw error; // Rethrow the error for handling in the calling function 77 | } 78 | } 79 | 80 | async delete(endpoint) { 81 | try { 82 | const response = await this.apiClient.delete(endpoint); 83 | return response; 84 | } catch (error) { 85 | throw error; // Rethrow the error for handling in the calling function 86 | } 87 | } 88 | } 89 | 90 | export default new ApiService(process.env.API_BASE_URL); // Set your base URL in environment variables 91 | -------------------------------------------------------------------------------- /src/services/dAppService.js: -------------------------------------------------------------------------------- 1 | // src/services/dAppService.js 2 | 3 | import apiClient from './apiService'; 4 | 5 | const dAppService = { 6 | getAllDApps: async () => { 7 | try { 8 | const response = await apiClient.get('/dapps'); 9 | return response.data; 10 | } catch (error) { 11 | throw error; // Propagate error to be handled by the calling function 12 | } 13 | }, 14 | 15 | createDApp: async (dAppData) => { 16 | try { 17 | const response = await apiClient.post('/dapps', dAppData); 18 | return response.data; 19 | } catch (error) { 20 | throw error; // Propagate error to be handled by the calling function 21 | } 22 | }, 23 | 24 | getDAppById: async (id) => { 25 | try { 26 | const response = await apiClient.get(`/dapps/${id}`); 27 | return response.data; 28 | } catch (error) { 29 | throw error; // Propagate error to be handled by the calling function 30 | } 31 | }, 32 | }; 33 | 34 | export default dAppService; 35 | -------------------------------------------------------------------------------- /src/services/marketplace-service.js: -------------------------------------------------------------------------------- 1 | // src/services/marketplace-service.js 2 | 3 | const AuthService = require('./authService'); 4 | const ProductService = require('./productService'); 5 | const OrderService = require('./orderService'); 6 | const ReviewService = require('./reviewService'); 7 | const PaymentService = require('./paymentService'); 8 | const NotificationService = require('./notificationService'); 9 | const UserProfileService = require('./userProfileService'); 10 | const WishlistService = require('./wishlistService'); 11 | const SearchService = require('./searchService'); 12 | const AdminService = require('./adminService'); 13 | const DiscountService = require('./discountService'); 14 | const RateLimiter = require('express-rate-limit'); // Rate limiting 15 | const CacheService = require('./cacheService'); // Caching service 16 | const LoggerService = require('./loggerService'); // Logging service 17 | const RecommendationService = require('./recommendationService'); // Recommendation service 18 | 19 | class MarketplaceService { 20 | constructor() { 21 | this.rateLimiter = RateLimiter({ 22 | windowMs: 15 * 60 * 1000, // 15 minutes 23 | max: 100 // Limit each IP to 100 requests per windowMs 24 | }); 25 | } 26 | 27 | // User Authentication 28 | async registerUser (username, password) { 29 | try { 30 | return await AuthService.register(username, password); 31 | } catch (error) { 32 | LoggerService.logError('Registration failed: ' + error.message); 33 | throw new Error('Registration failed: ' + error.message); 34 | } 35 | } 36 | 37 | async loginUser (username, password) { 38 | try { 39 | return await AuthService.login(username, password); 40 | } catch (error) { 41 | LoggerService.logError('Login failed: ' + error.message); 42 | throw new Error('Login failed: ' + error.message); 43 | } 44 | } 45 | 46 | async getUser Profile(userId) { 47 | try { 48 | return await UserProfileService.getUser Profile(userId); 49 | } catch (error) { 50 | LoggerService.logError('Failed to get user profile: ' + error.message); 51 | throw new Error('Failed to get user profile: ' + error.message); 52 | } 53 | } 54 | 55 | async updateUser Profile(userId, profileData) { 56 | try { 57 | return await UserProfileService.updateUser Profile(userId, profileData); 58 | } catch (error) { 59 | LoggerService.logError('Failed to update user profile: ' + error.message); 60 | throw new Error('Failed to update user profile: ' + error.message); 61 | } 62 | } 63 | 64 | // Product Management 65 | async createProduct(productData) { 66 | try { 67 | return await ProductService.createProduct(productData); 68 | } catch (error) { 69 | LoggerService.logError('Failed to create product: ' + error.message); 70 | throw new Error('Failed to create product: ' + error.message); 71 | } 72 | } 73 | 74 | async updateProduct(productId, productData) { 75 | try { 76 | return await ProductService.updateProduct(productId, productData); 77 | } catch (error) { 78 | LoggerService.logError('Failed to update product: ' + error.message); 79 | throw new Error('Failed to update product: ' + error.message); 80 | } 81 | } 82 | 83 | async deleteProduct(productId) { 84 | try { 85 | return await ProductService.deleteProduct(productId); 86 | } catch (error) { 87 | LoggerService.logError('Failed to delete product: ' + error.message); 88 | throw new Error('Failed to delete product: ' + error.message); 89 | } 90 | } 91 | 92 | async getProducts(query, page, limit) { 93 | try { 94 | const cacheKey = `products:${query}:${page}:${limit}`; 95 | const cachedProducts = await CacheService.get(cacheKey); 96 | if (cachedProducts) { 97 | return cachedProducts; 98 | } 99 | const products = await ProductService.getProducts(query, page, limit); 100 | await CacheService.set(cacheKey, products); 101 | return products; 102 | } catch (error) { 103 | LoggerService.logError('Failed to get products: ' + error.message); 104 | throw new Error('Failed to get products: ' + error.message); 105 | } 106 | } 107 | 108 | // Order Management 109 | async createOrder(orderData) { 110 | try { 111 | return await OrderService.createOrder(orderData); 112 | } catch (error) { 113 | LoggerService.logError('Failed to create order: ' + error.message); 114 | throw new Error('Failed to create order: ' + error.message); 115 | } 116 | } 117 | 118 | async getOrder(orderId) { 119 | try { 120 | return await OrderService.getOrder(orderId); 121 | } catch (error) { 122 | LoggerService.logError('Failed to get order: ' + error.message); 123 | throw new Error('Failed to get order: ' + error.message); 124 | } 125 | } 126 | 127 | async getUser Orders(userId) { 128 | try { 129 | return await OrderService.getUser Orders(userId); 130 | } catch (error) { 131 | LoggerService.logError('Failed to get user orders: ' + error.message); 132 | throw new Error('Failed to get user orders: ' + error.message); 133 | } 134 | } 135 | 136 | async trackOrder(orderId) { 137 | try { 138 | return await OrderService.trackOrder(orderId); 139 | } catch (error) { 140 | LoggerService.logError('Failed to track order: ' + error.message); 141 | throw new Error('Failed to track order: ' + error.message); 142 | } 143 | } 144 | 145 | // Review Management 146 | async addReview(productId, reviewData) { 147 | try { 148 | return await ReviewService.addReview(productId, reviewData); 149 | } catch (error) { 150 | LoggerService.logError('Failed to add review: ' + error.message); 151 | throw new Error('Failed to add review: ' + error.message); 152 | } 153 | } 154 | 155 | async getReviews(productId) { 156 | try { 157 | return await ReviewService.getReviews(productId); 158 | } catch (error) { 159 | LoggerService.logError('Failed to get reviews: ' + error.message); 160 | throw new Error('Failed to get reviews: ' + error.message); 161 | } 162 | } 163 | 164 | // Payment Processing 165 | async processPayment(paymentData) { 166 | try { 167 | return await PaymentService.processPayment(paymentData); 168 | } catch (error) { 169 | LoggerService.logError('Payment processing failed: ' + error.message); 170 | throw new Error('Payment processing failed: ' + error.message); 171 | } 172 | } 173 | 174 | // Notifications 175 | async sendNotification(userId, message) { 176 | try { 177 | return await NotificationService.sendNotification(userId, message); 178 | } catch (error) { 179 | LoggerService.logError('Failed to send notification: ' + error.message); 180 | throw new Error('Failed to send notification: ' + error.message); 181 | } 182 | } 183 | 184 | // Wishlist Management 185 | async addToWishlist(userId, productId) { 186 | try { 187 | return await WishlistService.addToWishlist(userId, productId); 188 | } catch (error) { 189 | LoggerService.logError('Failed to add to wishlist: ' + error.message); 190 | throw new Error('Failed to add to wishlist: ' + error.message); 191 | } 192 | } 193 | 194 | async getWishlist(userId) { 195 | try { 196 | return await WishlistService.getWishlist(userId); 197 | } catch (error) { 198 | LoggerService.logError('Failed to get wishlist: ' + error.message); 199 | throw new Error('Failed to get wishlist: ' + error.message); 200 | } 201 | } 202 | 203 | async removeFromWishlist(userId, productId) { 204 | try { 205 | return await WishlistService.removeFromWishlist(userId, productId); 206 | } catch (error) { 207 | LoggerService.logError('Failed to remove from wishlist: ' + error.message); 208 | throw new Error('Failed to remove from wishlist: ' + error.message); 209 | } 210 | } 211 | 212 | // Advanced Search 213 | async searchProducts(query, filters) { 214 | try { 215 | return await SearchService.searchProducts(query, filters); 216 | } catch (error) { 217 | LoggerService.logError('Failed to search products: ' + error.message); 218 | throw new Error('Failed to search products: ' + error.message); 219 | } 220 | } 221 | 222 | // Admin Functions 223 | async getAllProducts() { 224 | try { 225 | return await AdminService.getAllProducts(); 226 | } catch (error) { 227 | LoggerService.logError('Failed to get all products: ' + error.message); 228 | throw new Error('Failed to get all products: ' + error.message); 229 | } 230 | } 231 | 232 | async deleteProductById(productId) { 233 | try { 234 | return await AdminService.deleteProduct(productId); 235 | } catch (error) { 236 | LoggerService.logError('Failed to delete product by ID: ' + error.message); 237 | throw new Error('Failed to delete product by ID : ' + error.message); 238 | } 239 | } 240 | 241 | async updateProductById(productId, updateData) { 242 | try { 243 | return await AdminService.updateProduct(productId, updateData); 244 | } catch (error) { 245 | LoggerService.logError('Failed to update product by ID: ' + error.message); 246 | throw new Error('Failed to update product by ID: ' + error.message); 247 | } 248 | } 249 | 250 | // Discount Management 251 | async createDiscount(discountData) { 252 | try { 253 | return await DiscountService.createDiscount(discountData); 254 | } catch (error) { 255 | LoggerService.logError('Failed to create discount: ' + error.message); 256 | throw new Error('Failed to create discount: ' + error.message); 257 | } 258 | } 259 | 260 | async applyDiscount(orderId, discountCode) { 261 | try { 262 | return await DiscountService.applyDiscount(orderId, discountCode); 263 | } catch (error) { 264 | LoggerService.logError('Failed to apply discount: ' + error.message); 265 | throw new Error('Failed to apply discount: ' + error.message); 266 | } 267 | } 268 | 269 | // Recommendation System 270 | async getRecommendations(userId) { 271 | try { 272 | return await RecommendationService.getRecommendations(userId); 273 | } catch (error) { 274 | LoggerService.logError('Failed to get recommendations: ' + error.message); 275 | throw new Error('Failed to get recommendations: ' + error.message); 276 | } 277 | } 278 | } 279 | 280 | module.exports = new MarketplaceService(); 281 | -------------------------------------------------------------------------------- /src/services/userService.js: -------------------------------------------------------------------------------- 1 | // src/services/userService.js 2 | 3 | import apiService from './apiService'; 4 | 5 | class UserService { 6 | async register(userData) { 7 | try { 8 | const response = await apiService.post('/auth/register', userData); 9 | return response; // Assuming the response contains user data or a success message 10 | } catch (error) { 11 | throw this.handleError(error); 12 | } 13 | } 14 | 15 | async login(credentials) { 16 | try { 17 | const response = await apiService.post('/auth/login', credentials); 18 | return response; // Assuming the response contains a token or user data 19 | } catch (error) { 20 | throw this.handleError(error); 21 | } 22 | } 23 | 24 | async getUser Details(userId) { 25 | try { 26 | const response = await apiService.get(`/users/${userId}`); 27 | return response; // Assuming the response contains user details 28 | } catch (error) { 29 | throw this.handleError(error); 30 | } 31 | } 32 | 33 | async updateUser (userId, userData) { 34 | try { 35 | const response = await apiService.put(`/users/${userId}`, userData); 36 | return response; // Assuming the response contains updated user data 37 | } catch (error) { 38 | throw this.handleError(error); 39 | } 40 | } 41 | 42 | async deleteUser (userId) { 43 | try { 44 | const response = await apiService.delete(`/users/${userId}`); 45 | return response; // Assuming the response contains a success message 46 | } catch (error) { 47 | throw this.handleError(error); 48 | } 49 | } 50 | 51 | handleError(error) { 52 | // Customize error handling based on your application's needs 53 | if (error.status === 401) { 54 | return new Error('Unauthorized access. Please log in again.'); 55 | } else if (error.status === 404) { 56 | return new Error('User not found.'); 57 | } else { 58 | return new Error(error.message || 'An unexpected error occurred.'); 59 | } 60 | } 61 | } 62 | 63 | export default new UserService(); 64 | -------------------------------------------------------------------------------- /src/utils/helpers.js: -------------------------------------------------------------------------------- 1 | // src/utils/helpers.js 2 | 3 | const { v4: uuidv4 } = require('uuid'); 4 | 5 | /** 6 | * Generate a unique identifier 7 | * @returns {string} - A unique identifier 8 | */ 9 | const generateUniqueId = () => { 10 | return uuidv4(); 11 | }; 12 | 13 | /** 14 | * Format a date to a readable string 15 | * @param {Date} date - The date to format 16 | * @returns {string} - Formatted date string 17 | */ 18 | const formatDate = (date) => { 19 | return date.toISOString().split('T')[0]; // YYYY-MM-DD format 20 | }; 21 | 22 | /** 23 | * Deep clone an object 24 | * @param {Object} obj - The object to clone 25 | * @returns {Object} - A deep clone of the object 26 | */ 27 | const deepClone = (obj) => { 28 | return JSON.parse(JSON.stringify(obj)); 29 | }; 30 | 31 | /** 32 | * Check if an object is empty 33 | * @param {Object} obj - The object to check 34 | * @returns {boolean} - True if empty, false otherwise 35 | */ 36 | const isEmptyObject = (obj) => { 37 | return Object.keys(obj).length === 0; 38 | }; 39 | 40 | /** 41 | * Delay execution for a specified amount of time 42 | * @param {number} ms - The number of milliseconds to delay 43 | * @returns {Promise} - A promise that resolves after the delay 44 | */ 45 | const delay = (ms) => { 46 | return new Promise(resolve => setTimeout(resolve, ms)); 47 | }; 48 | 49 | module.exports = { 50 | generateUniqueId, 51 | formatDate, 52 | deepClone, 53 | isEmptyObject, 54 | delay, 55 | }; 56 | -------------------------------------------------------------------------------- /src/utils/validators.js: -------------------------------------------------------------------------------- 1 | // src/utils/validators.js 2 | 3 | const emailRegex = /^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$/; 4 | const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[A-Za-z\d@$!%*?&]{8,}$/; // At least 8 characters, 1 uppercase, 1 lowercase, 1 number 5 | 6 | /** 7 | * Validate email format 8 | * @param {string} email - The email address to validate 9 | * @returns {boolean} - True if valid, false otherwise 10 | */ 11 | const validateEmail = (email) => { 12 | return emailRegex.test(email); 13 | }; 14 | 15 | /** 16 | * Validate password strength 17 | * @param {string} password - The password to validate 18 | * @returns {boolean} - True if valid, false otherwise 19 | */ 20 | const validatePassword = (password) => { 21 | return passwordRegex.test(password); 22 | }; 23 | 24 | /** 25 | * Validate if a string is not empty 26 | * @param {string} str - The string to validate 27 | * @returns {boolean} - True if not empty, false otherwise 28 | */ 29 | const validateNotEmpty = (str) => { 30 | return str && str.trim().length > 0; 31 | }; 32 | 33 | /** 34 | * Validate if a number is within a specified range 35 | * @param {number} num - The number to validate 36 | * @param {number} min - The minimum value 37 | * @param {number} max - The maximum value 38 | * @returns {boolean} - True if within range, false otherwise 39 | */ 40 | const validateNumberInRange = (num, min, max) => { 41 | return typeof num === 'number' && num >= min && num <= max; 42 | }; 43 | 44 | module.exports = { 45 | validateEmail, 46 | validatePassword, 47 | validateNotEmpty, 48 | validateNumberInRange, 49 | }; 50 | -------------------------------------------------------------------------------- /tests/e2e/app.test.js: -------------------------------------------------------------------------------- 1 | // tests/e2e/app.test.js 2 | 3 | const request = require('supertest'); 4 | const app = require('../../src/app'); // Your Express app 5 | const mongoose = require('mongoose'); 6 | 7 | beforeAll(async () => { 8 | await mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true }); 9 | }); 10 | 11 | afterAll(async () => { 12 | await mongoose.connection.close(); 13 | }); 14 | 15 | describe('End-to-End Application Tests', () => { 16 | test('User registration and login flow', async () => { 17 | // Register a new user 18 | const registerResponse = await request(app) 19 | .post('/api/users') 20 | .send({ username: 'testuser', email: 'test@example.com', password: 'Password123!' }); 21 | 22 | expect(registerResponse.status).toBe(201); 23 | expect(registerResponse.body).toHaveProperty('user'); 24 | 25 | // Login the user 26 | const loginResponse = await request(app) 27 | .post('/api/auth/login') 28 | .send({ email: 'test@example.com', password: 'Password123!' }); 29 | 30 | expect(loginResponse.status).toBe(200); 31 | expect(loginResponse.body).toHaveProperty('token'); 32 | }); 33 | 34 | test('Create and retrieve a dApp', async () => { 35 | // Register a new user 36 | const registerResponse = await request(app) 37 | .post('/api/users') 38 | .send({ username: 'testuser', email: 'test@example.com', password: 'Password123!' }); 39 | 40 | const userId = registerResponse.body.user._id; 41 | 42 | // Login the user to get the token 43 | const loginResponse = await request(app) 44 | .post('/api/auth/login') 45 | .send({ email: 'test@example.com', password: 'Password123!' }); 46 | 47 | const token = loginResponse.body.token; 48 | 49 | // Create a new dApp 50 | const dAppResponse = await request(app) 51 | .post('/api/dapps') 52 | .set('Authorization', `Bearer ${token}`) 53 | .send({ name: 'Test dApp', description: 'A test decentralized application', url: 'http://testdapp.com', createdBy: userId }); 54 | 55 | expect(dAppResponse.status).toBe(201); 56 | expect(dAppResponse.body).toHaveProperty('dApp'); 57 | 58 | // Retrieve the dApp 59 | const getDAppResponse = await request(app).get(`/api/dapps/${dAppResponse.body.dApp._id}`); 60 | expect(getDAppResponse.status).toBe(200); 61 | expect(getDAppResponse.body).toHaveProperty('dApp'); 62 | expect(getDAppResponse.body.dApp._id).toBe(dAppResponse.body.dApp._id); 63 | }); 64 | 65 | test('User should not be able to access protected routes without a token', async () => { 66 | const response = await request(app).get('/api/dapps'); 67 | expect(response.status).toBe(401); // Unauthorized 68 | }); 69 | 70 | test('User should be able to access protected routes with a valid token', async () => { 71 | // Register a new user 72 | const registerResponse = await request(app) 73 | .post('/api/users') 74 | .send({ username: 'testuser', email: 'test@example.com', password: 'Password123!' }); 75 | 76 | // Login the user to get the token 77 | const loginResponse = await request(app) 78 | .post('/api/auth/login') 79 | .send({ email: 'test@example.com', password: 'Password123!' }); 80 | 81 | const token = loginResponse.body.token; 82 | 83 | // Access protected route 84 | const protectedResponse = await request(app) 85 | .get('/api/dapps') 86 | .set('Authorization', `Bearer ${token}`); 87 | 88 | expect(protectedResponse.status).toBe(200); 89 | expect(Array.isArray(protectedResponse.body.dApps)).toBe(true); 90 | }); 91 | }); 92 | -------------------------------------------------------------------------------- /tests/integration/api.test.js: -------------------------------------------------------------------------------- 1 | // tests/integration/api.test.js 2 | 3 | const request = require('supertest'); 4 | const app = require('../../src/app'); // Your Express app 5 | const mongoose = require('mongoose'); 6 | 7 | beforeAll(async () => { 8 | await mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true }); 9 | }); 10 | 11 | afterAll(async () => { 12 | await mongoose.connection.close(); 13 | }); 14 | 15 | describe('API Endpoints', () => { 16 | let userId; 17 | let token; 18 | 19 | beforeEach(async () => { 20 | // Clean up the database before each test 21 | await mongoose.connection.db.dropDatabase(); 22 | 23 | // Register a new user for testing 24 | const registerResponse = await request(app) 25 | .post('/api/users') 26 | .send({ username: 'testuser', email: 'test@example.com', password: 'Password123!' }); 27 | 28 | userId = registerResponse.body.user._id; 29 | 30 | // Login the user to get the token 31 | const loginResponse = await request(app) 32 | .post('/api/auth/login') 33 | .send({ email: 'test@example.com', password: 'Password123!' }); 34 | 35 | token = loginResponse.body.token; 36 | }); 37 | 38 | test('POST /api/users should create a new user', async () => { 39 | const response = await request(app) 40 | .post('/api/users') 41 | .send({ username: 'newuser', email: 'newuser@example.com', password: 'Password123!' }); 42 | 43 | expect(response.status).toBe(201); 44 | expect(response.body).toHaveProperty('user'); 45 | expect(response.body.user.email).toBe('newuser@example.com'); 46 | }); 47 | 48 | test('GET /api/users/:id should return a user', async () => { 49 | const response = await request(app).get(`/api/users/${userId}`); 50 | expect(response.status).toBe(200); 51 | expect(response.body).toHaveProperty('user'); 52 | expect(response.body.user._id).toBe(userId); 53 | }); 54 | 55 | test('GET /api/users should return all users', async () => { 56 | const response = await request(app).get('/api/users'); 57 | expect(response.status).toBe(200); 58 | expect(Array.isArray(response.body.users)).toBe(true); 59 | }); 60 | 61 | test('POST /api/dapps should create a new dApp', async () => { 62 | const response = await request(app) 63 | .post('/api/dapps') 64 | .set('Authorization', `Bearer ${token}`) 65 | .send({ name: 'Test dApp', description: 'A test decentralized application', url: 'http://testdapp.com', createdBy: userId }); 66 | 67 | expect(response.status).toBe(201); 68 | expect(response.body).toHaveProperty('dApp'); 69 | expect(response.body.dApp.name).toBe('Test dApp'); 70 | }); 71 | 72 | test('GET /api/dapps/:id should return a dApp', async () => { 73 | // Create a dApp to test the GET endpoint 74 | const dAppResponse = await request(app) 75 | .post('/api/dapps') 76 | .set('Authorization', `Bearer ${token}`) 77 | .send({ name: 'Test dApp', description: 'A test decentralized application', url: 'http://testdapp.com', createdBy: userId }); 78 | 79 | const dAppId = dAppResponse.body.dApp._id; 80 | 81 | const response = await request(app).get(`/api/dapps/${dAppId}`); 82 | expect(response.status).toBe(200); 83 | expect(response.body).toHaveProperty('dApp'); 84 | expect(response.body.dApp._id).toBe(dAppId); 85 | }); 86 | 87 | test('GET /api/dapps should return all dApps', async () => { 88 | const response = await request(app) 89 | .get('/api/dapps') 90 | .set('Authorization', `Bearer ${token}`); 91 | 92 | expect(response.status).toBe(200); 93 | expect(Array.isArray(response.body.dApps)).toBe(true); 94 | }); 95 | 96 | test('GET /api/dapps should return 401 if no token is provided', async () => { 97 | const response = await request(app).get('/api/dapps'); 98 | expect(response.status).toBe(401); // Unauthorized 99 | }); 100 | }); 101 | -------------------------------------------------------------------------------- /tests/unit/dAppService.test.js: -------------------------------------------------------------------------------- 1 | // tests/unit/dAppService.test.js 2 | 3 | const dAppService = require('../../src/services/dAppService'); 4 | const dApp = require('../../src/models/dApp'); 5 | 6 | jest.mock('../../src/models/dApp'); 7 | 8 | describe('dApp Service', () => { 9 | beforeEach(() => { 10 | jest.clearAllMocks(); 11 | }); 12 | 13 | test('should create a new dApp', async () => { 14 | const dAppData = { name: 'Test dApp', description: 'A test decentralized application', url: 'http://testdapp.com', createdBy: 'userId' }; 15 | dApp.prototype.save = jest.fn().mockResolvedValue(dAppData); 16 | 17 | const createdDApp = await dAppService.createDApp(dAppData); 18 | expect(createdDApp).toEqual(dAppData); 19 | expect(dApp.prototype.save).toHaveBeenCalled(); 20 | }); 21 | 22 | test('should find a dApp by name', async () => { 23 | const dAppData = { name: 'Test dApp', description: 'A test decentralized application', url: 'http://testdapp.com', createdBy: 'userId' }; 24 | dApp.findOne = jest.fn().mockResolvedValue(dAppData); 25 | 26 | const foundDApp = await dAppService.findDAppByName('Test dApp'); 27 | expect(foundDApp).toEqual(dAppData); 28 | expect(dApp.findOne).toHaveBeenCalledWith({ name: 'Test dApp' }); 29 | }); 30 | 31 | test('should throw an error if dApp not found', async () => { 32 | dApp.findOne = jest.fn().mockResolvedValue(null); 33 | 34 | await expect(dAppService.findDAppByName('Not Found dApp')).rejects.toThrow('dApp not found'); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /tests/unit/userService.test.js: -------------------------------------------------------------------------------- 1 | // tests/unit/userService.test.js 2 | 3 | const userService = require('../../src/services/userService'); 4 | const User = require('../../src/models/User'); 5 | 6 | jest.mock('../../src/models/User'); 7 | 8 | describe('User Service', () => { 9 | beforeEach(() => { 10 | jest.clearAllMocks(); 11 | }); 12 | 13 | test('should create a new user', async () => { 14 | const userData = { username: 'testuser', email: 'test@example.com', password: 'Password123!' }; 15 | User.prototype.save = jest.fn().mockResolvedValue(userData); 16 | 17 | const user = await userService.createUser (userData); 18 | expect(user).toEqual(userData); 19 | expect(User.prototype.save).toHaveBeenCalled(); 20 | }); 21 | 22 | test('should find a user by email', async () => { 23 | const userData = { username: 'testuser', email: 'test@example.com', password: 'Password123!' }; 24 | User.findOne = jest.fn().mockResolvedValue(userData); 25 | 26 | const user = await userService.findUser ByEmail('test@example.com'); 27 | expect(user).toEqual(userData); 28 | expect(User.findOne).toHaveBeenCalledWith({ email: 'test@example.com' }); 29 | }); 30 | 31 | test('should throw an error if user not found', async () => { 32 | User.findOne = jest.fn().mockResolvedValue(null); 33 | 34 | await expect(userService.findUser ByEmail('notfound@example.com')).rejects.toThrow('User not found'); 35 | }); 36 | }); 37 | --------------------------------------------------------------------------------