-
-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Integrate GBIF API to display biodiversity data #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feat/initial-project-structure
Are you sure you want to change the base?
feat: Integrate GBIF API to display biodiversity data #2
Conversation
This commit integrates the Global Biodiversity Information Facility (GBIF) API to fetch and display species occurrence data. - A new backend endpoint `/api/gbif_occurrences` is added to the Flask application to fetch the 5 most recent species occurrences from Togo. - The frontend is updated with a new section to display the data, including the species name and a link to the occurrence on the GBIF website. - The README.md is updated to document the new API integration.
Reviewer's GuideThis PR integrates the GBIF API by adding a new backend endpoint to fetch recent species occurrences in Togo, updating the frontend to render this data in a dedicated section, and extending project documentation to describe the new integration. Sequence diagram for fetching and displaying GBIF occurrencessequenceDiagram
participant User
participant Frontend
participant Backend
participant GBIF_API
User->>Frontend: Load page
Frontend->>Backend: GET /api/gbif_occurrences
Backend->>GBIF_API: GET occurrence/search?country=TG&limit=5
GBIF_API-->>Backend: JSON occurrence data
Backend-->>Frontend: JSON formatted species data
Frontend-->>User: Render species list with links
Class diagram for GBIF occurrence data structureclassDiagram
class GBIFOccurrence {
+species: string
+url: string
}
class GBIFAPIResponse {
+results: list~GBIFOccurrence~
}
GBIFAPIResponse "1" -- "*" GBIFOccurrence: contains
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Insecure Processing of Data (2)
More info on how to fix Insecure Processing of Data in Python and JavaScript. 👉 Go to the dashboard for detailed results. 📥 Happy? Share your feedback with us. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there - I've reviewed your changes and found some issues that need to be addressed.
Blocking issues:
- 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'. (link)
- User controlled data in methods like
innerHTML,outerHTMLordocument.writeis an anti-pattern that can lead to XSS vulnerabilities (link) - User controlled data in a
gbifOccurrencesContainer.innerHTMLis an anti-pattern that can lead to XSS vulnerabilities (link) - User controlled data in methods like
innerHTML,outerHTMLordocument.writeis an anti-pattern that can lead to XSS vulnerabilities (link) - User controlled data in a
gbifOccurrencesContainer.innerHTMLis an anti-pattern that can lead to XSS vulnerabilities (link) - User controlled data in methods like
innerHTML,outerHTMLordocument.writeis an anti-pattern that can lead to XSS vulnerabilities (link) - User controlled data in a
gbifOccurrencesContainer.innerHTMLis an anti-pattern that can lead to XSS vulnerabilities (link)
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `eco_project/backend/app.py:48-58` </location>
<code_context>
+ response = requests.get(url)
+ data = response.json()
+
+ if data and data['results']:
+ # Clean and format the data
+ formatted_data = []
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Check for 'results' key existence before accessing.
Using 'data.get('results')' instead of 'data['results']' will prevent potential KeyErrors if 'results' is missing from the response.
```suggestion
if data and data.get('results'):
# Clean and format the data
formatted_data = []
for entry in data.get('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
```
</issue_to_address>
### Comment 2
<location> `eco_project/backend/app.py:52-54` </location>
<code_context>
+ # Clean and format the data
+ formatted_data = []
+ 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)
</code_context>
<issue_to_address>
**issue:** Handle missing 'key' in GBIF results gracefully.
Using 'entry.get('key')' with a default value or skipping entries without 'key' will prevent KeyError exceptions.
</issue_to_address>
### Comment 3
<location> `eco_project/frontend/script.js:74` </location>
<code_context>
+
+ let html = '<ul>';
+ data.forEach(item => {
+ html += `<li><a href="${item.url}" target="_blank">${item.species}</a></li>`;
+ });
+ html += '</ul>';
</code_context>
<issue_to_address>
**🚨 issue (security):** Escape HTML to prevent XSS vulnerabilities.
Escaping 'item.species' and 'item.url' before rendering will help prevent XSS if backend data is not sanitized.
</issue_to_address>
### Comment 4
<location> `eco_project/backend/app.py:45` </location>
<code_context>
response = requests.get(url)
</code_context>
<issue_to_address>
**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'.
```suggestion
response = requests.get(url, timeout=30)
```
*Source: opengrep*
</issue_to_address>
### Comment 5
<location> `eco_project/frontend/script.js:68` </location>
<code_context>
gbifOccurrencesContainer.innerHTML = `<p>Error fetching data: ${data.error}</p>`;
</code_context>
<issue_to_address>
**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*
</issue_to_address>
### Comment 6
<location> `eco_project/frontend/script.js:68` </location>
<code_context>
gbifOccurrencesContainer.innerHTML = `<p>Error fetching data: ${data.error}</p>`;
</code_context>
<issue_to_address>
**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*
</issue_to_address>
### Comment 7
<location> `eco_project/frontend/script.js:78` </location>
<code_context>
gbifOccurrencesContainer.innerHTML = html;
</code_context>
<issue_to_address>
**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*
</issue_to_address>
### Comment 8
<location> `eco_project/frontend/script.js:78` </location>
<code_context>
gbifOccurrencesContainer.innerHTML = html;
</code_context>
<issue_to_address>
**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*
</issue_to_address>
### Comment 9
<location> `eco_project/frontend/script.js:81` </location>
<code_context>
gbifOccurrencesContainer.innerHTML = `<p>Error fetching data: ${error.message}</p>`;
</code_context>
<issue_to_address>
**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*
</issue_to_address>
### Comment 10
<location> `eco_project/frontend/script.js:81` </location>
<code_context>
gbifOccurrencesContainer.innerHTML = `<p>Error fetching data: ${error.message}</p>`;
</code_context>
<issue_to_address>
**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*
</issue_to_address>
### Comment 11
<location> `eco_project/frontend/script.js:59-83` </location>
<code_context>
</code_context>
<issue_to_address>
**issue (code-quality):** Avoid function declarations, favouring function assignment expressions, inside blocks. ([`avoid-function-declarations-in-blocks`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/JavaScript/Default-Rules/avoid-function-declarations-in-blocks))
<details><summary>Explanation</summary>Function declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers.
Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you
should use function expressions, which create functions in-scope.
</details>
</issue_to_address>
### Comment 12
<location> `eco_project/backend/app.py:50` </location>
<code_context>
@app.route('/api/gbif_occurrences')
def gbif_occurrences():
# GBIF API URL for occurrences in Togo
url = "https://api.gbif.org/v1/occurrence/search?country=TG&limit=5"
try:
response = requests.get(url)
data = response.json()
if data and data['results']:
# Clean and format the data
formatted_data = []
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
</code_context>
<issue_to_address>
**issue (code-quality):** Convert for loop into list comprehension ([`list-comprehension`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/list-comprehension/))
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
eco_project/frontend/script.js
Outdated
| async function fetchGbifData() { | ||
| try { | ||
| const response = await fetch('/api/gbif_occurrences'); | ||
| 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>`; | ||
| return; | ||
| } | ||
|
|
||
| let html = '<ul>'; | ||
| data.forEach(item => { | ||
| html += `<li><a href="${item.url}" target="_blank">${item.species}</a></li>`; | ||
| }); | ||
| html += '</ul>'; | ||
|
|
||
| gbifOccurrencesContainer.innerHTML = html; | ||
|
|
||
| } catch (error) { | ||
| gbifOccurrencesContainer.innerHTML = `<p>Error fetching data: ${error.message}</p>`; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (code-quality): Avoid function declarations, favouring function assignment expressions, inside blocks. (avoid-function-declarations-in-blocks)
Explanation
Function declarations may be hoisted in Javascript, but the behaviour is inconsistent between browsers. Hoisting is generally confusing and should be avoided. Rather than using function declarations inside blocks, you should use function expressions, which create functions in-scope.|
|
||
| if data and data['results']: | ||
| # Clean and format the data | ||
| formatted_data = [] |
There was a problem hiding this comment.
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)
This commit adds a feature to search for species occurrences by country using the GBIF API. - The backend endpoint `/api/gbif_occurrences` is updated to accept a `country` parameter. - The frontend is updated with a search box to allow users to enter a country code and view the results. - The README.md is updated to document the new search functionality.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New security issues found
| 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) | ||
| data = response.json() | ||
|
|
||
| if data and data['results']: | ||
| # Clean and format the data | ||
| formatted_data = [] | ||
| 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 |
There was a problem hiding this comment.
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
| url = f"https://api.gbif.org/v1/occurrence/search?country={country_code}&limit=5" | ||
|
|
||
| try: | ||
| response = requests.get(url) |
There was a problem hiding this comment.
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'.
| response = requests.get(url) | |
| response = requests.get(url, timeout=30) |
Source: opengrep
| const data = await response.json(); | ||
|
|
||
| if (data.error) { | ||
| gbifOccurrencesContainer.innerHTML = `<p>Error fetching data: ${data.error}</p>`; |
There was a problem hiding this comment.
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
| const data = await response.json(); | ||
|
|
||
| if (data.error) { | ||
| gbifOccurrencesContainer.innerHTML = `<p>Error fetching data: ${data.error}</p>`; |
There was a problem hiding this comment.
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
| }); | ||
| html += '</ul>'; | ||
|
|
||
| gbifOccurrencesContainer.innerHTML = html; |
There was a problem hiding this comment.
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
| }); | ||
| html += '</ul>'; | ||
|
|
||
| gbifOccurrencesContainer.innerHTML = html; |
There was a problem hiding this comment.
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
| gbifOccurrencesContainer.innerHTML = html; | ||
|
|
||
| } catch (error) { | ||
| gbifOccurrencesContainer.innerHTML = `<p>Error fetching data: ${error.message}</p>`; |
There was a problem hiding this comment.
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
| gbifOccurrencesContainer.innerHTML = html; | ||
|
|
||
| } catch (error) { | ||
| gbifOccurrencesContainer.innerHTML = `<p>Error fetching data: ${error.message}</p>`; |
There was a problem hiding this comment.
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
This commit adds a feature to search for species occurrences by country using the GBIF API. - The backend endpoint `/api/gbif_occurrences` is updated to accept a `country` parameter. - The frontend is updated with a search box to allow users to enter a country code and view the results. - The README.md is updated to document the new search functionality.
This commit integrates the Global Biodiversity Information Facility (GBIF) API to fetch and display species occurrence data.
/api/gbif_occurrencesis added to the Flask application to fetch the 5 most recent species occurrences from Togo.Summary by Sourcery
Integrate GBIF API to fetch and display recent species occurrence data for Togo by adding a new backend endpoint, updating the frontend to show the data, and updating documentation.
New Features:
/api/gbif_occurrencesFlask endpoint to retrieve the 5 latest species occurrences from GBIF for TogoDocumentation: