Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ This project is a web application designed to promote environmental protection a

This application integrates with the World Bank API to fetch and display data on environmental indicators. Currently, it displays the forest area percentage for Brazil, Indonesia, and the Democratic Republic of Congo.

## GBIF API Integration

This application also integrates with the Global Biodiversity Information Facility (GBIF) API to fetch and display species occurrence data. Users can search for the 5 most recent occurrences in any country by providing a 2-letter country code. By default, it displays the data for Togo.

## Usage

To run this project locally, you will need to have Python and Flask installed.
Expand Down
29 changes: 28 additions & 1 deletion eco_project/backend/app.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from flask import Flask, jsonify
from flask import Flask, jsonify, request
import requests

app = Flask(__name__)
Expand Down Expand Up @@ -36,5 +36,32 @@ def forest_area():
except requests.exceptions.RequestException as e:
return jsonify({"error": str(e)}), 500

@app.route('/api/gbif_occurrences')
def gbif_occurrences():
# Get country code from request arguments, default to Togo (TG)
country_code = request.args.get('country', 'TG')

# GBIF API URL for occurrences
url = f"https://api.gbif.org/v1/occurrence/search?country={country_code}&limit=5"

try:
response = requests.get(url)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (python.requests.best-practice.use-timeout): Detected a 'requests' call without a timeout set. By default, 'requests' calls wait until the connection is closed. This means a 'requests' call without a timeout will hang the program if a response is never received. Consider setting a timeout for all 'requests'.

Suggested change
response = requests.get(url)
response = requests.get(url, timeout=30)

Source: opengrep

data = response.json()

if data and data['results']:
# Clean and format the data
formatted_data = []
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (code-quality): Convert for loop into list comprehension (list-comprehension)

for entry in data['results']:
formatted_data.append({
'species': entry.get('scientificName', 'N/A'),
'url': f"https://www.gbif.org/occurrence/{entry['key']}"
})
return jsonify(formatted_data)
else:
return jsonify({"error": "No data found for the selected criteria."}), 404

except requests.exceptions.RequestException as e:
return jsonify({"error": str(e)}), 500
Comment on lines +42 to +64
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (python.django.security.injection.ssrf.ssrf-injection-requests): Data from request object is passed to a new server-side request. This could lead to a server-side request forgery (SSRF). To mitigate, ensure that schemes and hosts are validated against an allowlist, do not forward the response to the user, and ensure proper authentication and transport-layer security in the proxied request. See https://owasp.org/www-community/attacks/Server_Side_Request_Forgery to learn more about SSRF vulnerabilities.

Source: opengrep


if __name__ == '__main__':
app.run(debug=True)
7 changes: 7 additions & 0 deletions eco_project/frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ <h2>Development Projects</h2>
<p>Tracking and managing sustainable development goals. Here is some data from the World Bank:</p>
<div id="world-bank-data"></div>
</section>
<section id="gbif-data">
<h2>Biodiversity Search</h2>
<p>Enter a 2-letter country code (e.g., TG for Togo, US for United States) to search for recent species occurrences from the Global Biodiversity Information Facility (GBIF).</p>
<input type="text" id="country-code-input" placeholder="Enter country code...">
<button id="search-gbif-btn">Search</button>
<div id="gbif-occurrences"></div>
</section>
<section id="ai-agent">
<h2>AI Assistant</h2>
<p>Your personal guide to environmental protection.</p>
Expand Down
38 changes: 38 additions & 0 deletions eco_project/frontend/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@ document.addEventListener('DOMContentLoaded', () => {
const chatInput = document.getElementById('chat-input');
const chatWindow = document.getElementById('chat-window');
const worldBankDataContainer = document.getElementById('world-bank-data');
const gbifOccurrencesContainer = document.getElementById('gbif-occurrences');
const countryCodeInput = document.getElementById('country-code-input');
const searchGbifBtn = document.getElementById('search-gbif-btn');

// Fetch and display World Bank data on page load
fetchWorldBankData();
// Fetch and display GBIF data for Togo on page load
fetchGbifData('TG');

sendBtn.addEventListener('click', () => {
const userInput = chatInput.value;
Expand All @@ -20,6 +25,13 @@ document.addEventListener('DOMContentLoaded', () => {
}
});

searchGbifBtn.addEventListener('click', () => {
const countryCode = countryCodeInput.value.trim().toUpperCase();
if (countryCode) {
fetchGbifData(countryCode);
}
});

function appendMessage(message) {
const messageElement = document.createElement('p');
messageElement.textContent = message;
Expand Down Expand Up @@ -52,4 +64,30 @@ document.addEventListener('DOMContentLoaded', () => {
worldBankDataContainer.innerHTML = `<p>Error fetching data: ${error.message}</p>`;
}
}

async function fetchGbifData(countryCode) {
try {
const response = await fetch(`/api/gbif_occurrences?country=${countryCode}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();

if (data.error) {
gbifOccurrencesContainer.innerHTML = `<p>Error fetching data: ${data.error}</p>`;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (javascript.browser.security.insecure-document-method): User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (javascript.browser.security.insecure-innerhtml): User controlled data in a gbifOccurrencesContainer.innerHTML is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

return;
}

let html = '<ul>';
data.forEach(item => {
html += `<li><a href="${item.url}" target="_blank">${item.species}</a></li>`;
});
html += '</ul>';

gbifOccurrencesContainer.innerHTML = html;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (javascript.browser.security.insecure-document-method): User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (javascript.browser.security.insecure-innerhtml): User controlled data in a gbifOccurrencesContainer.innerHTML is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep


} catch (error) {
gbifOccurrencesContainer.innerHTML = `<p>Error fetching data: ${error.message}</p>`;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (javascript.browser.security.insecure-document-method): User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security (javascript.browser.security.insecure-innerhtml): User controlled data in a gbifOccurrencesContainer.innerHTML is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

}
}
});
Loading