Merge remote-tracking branch 'refs/remotes/origin/main'

This commit is contained in:
Ugric committed 2026-04-06 15:49:40 +01:00
commit 9284f4e3b1
12 files changed
+223 -8

No files matched your search

+22
View File
@@ -92,6 +92,16 @@ def get_all_species():
with get_db() as conn:
rows = conn.execute("SELECT * FROM species").fetchall()
return [dict(row) for row in rows]
def get_all_articles():
with get_db() as conn:
rows = conn.execute("SELECT * FROM articles").fetchall()
return [dict(row) for row in rows]
def get_article_by_id(id):
with get_db() as conn:
row = conn.execute("SELECT * FROM articles WHERE article_id = ? LIMIT 1", (id,)).fetchone()
return dict(row) if row else None
def get_species_by_name(species_english):
@@ -127,6 +137,18 @@ WHERE
(query.lower(),)
).fetchall()
return [dict(row) for row in rows]
def search_articles(query):
with get_db() as conn:
rows = conn.execute("""SELECT * FROM articles WHERE
instr(LOWER(COALESCE(CAST(article_id AS TEXT), '')), ?1) > 0
OR instr(LOWER(COALESCE(CAST(title AS TEXT), '')), ?1) > 0
OR instr(LOWER(COALESCE(CAST(subtitle AS TEXT), '')), ?1) > 0
OR instr(LOWER(COALESCE(CAST(author AS TEXT), '')), ?1) > 0
OR instr(LOWER(COALESCE(CAST(publish_date AS TEXT), '')), ?1) > 0;""",
(query.lower(),)
).fetchall()
return [dict(row) for row in rows]
def delete_species(species_id):
with get_db() as conn:
+62 -1
View File
@@ -91,7 +91,27 @@ SEED_SPECIES = [
"photoid": "celebes crested macaque"
},
]
test_article = [
{
"article_id":"a-starrier-night",
"title" :"A Starrier Night",
"subtitle" :("In the past decade, our planet has rapidly lost its night sky. In response,"
"West Texas created the largest international dark-sky reserve on Earth."),
"main_text" :("Light pollution has been growing rapidly, with the sky brightening nearly 10% each year "
"since 2011. In West Texas, the McDonald Observatory—the darkest observatory in the "
"continental US—faced an operational threat as development crept into the region. "
"Superintendent Teznie Pugh and colleagues partnered with local landowners, parks, and "
"The Nature Conservancy to protect the night sky. In 2022, DarkSky International certified "
"the Greater Big Bend International Dark Sky Reserve, covering 9.6 million acres and "
"spanning the US-Mexico border—the largest International Dark Sky Reserve in the world. "
"The Davis Mountains Preserve (33,000 acres) forms the core of the reserve. The greatest "
"ongoing threat comes from oil and gas development in the Permian Basin. The reserve also "
"supports ecological research into the effects of light pollution on nocturnal wildlife, "
"plants, and ecosystems."),
"author" :"Jenny Rogers",
"publish_date":"2026-02-13"
}
]
def init_database():
with get_db() as conn:
@@ -110,6 +130,46 @@ def init_database():
print("Database initialised.")
seed_species()
def init_articles():
with get_db() as conn:
# table for articles in library
conn.execute("""
CREATE TABLE IF NOT EXISTS articles (
article_id TEXT PRIMARY KEY UNIQUE,
title TEXT,
subtitle TEXT,
main_text TEXT,
author TEXT,
publish_date);""")
print("Successfully created/found articles table.")
# table to store links relevant to articles (e.g. sources or original article)
conn.execute("""
CREATE TABLE IF NOT EXISTS article_links (
link_id INTEGER PRIMARY KEY AUTOINCREMENT,
article_id TEXT NOT NULL,
url TEXT NOT NULL,
link_text TEXT,
FOREIGN KEY (article_id) REFERENCES articles(article_id)
ON DELETE CASCADE);""")
print("Succesfully found/created article_links table.")
for article in test_article:
table_exists = conn.execute(
"SELECT article_id FROM articles WHERE article_id = ?",
(article["article_id"],)).fetchone()
if table_exists:
print(f" SKIP {article['article_id']} (already exists)")
continue
conn.execute("""
INSERT INTO articles
(article_id, title, subtitle, main_text, author, publish_date)
VALUES (?, ?, ?, ?, ?, ?)""",
(article["article_id"],
article["title"],
article["subtitle"],
article["main_text"],
article["author"],
article["publish_date"],))
print(f" ADD {article['article_id']}")
def seed_species():
with get_db() as conn:
@@ -224,4 +284,5 @@ init_database()
init_accounts_database()
init_classes_database()
init_programs_database()
init_articles()
register_user("admin", "admin@komodohub.org", "admin", "admin")
Binary file not shown.
+32
View File
@@ -0,0 +1,32 @@
from flask import render_template, Blueprint, send_from_directory
from database.db_commands import get_article_by_id, get_species_by_id
import sqlite3
page = Blueprint("article", __name__)
# this page works by taking the species name (in english) from the url and using that to read the database.
# Because of this we are able to create one page and simply generate links based on the contents of the database
# i.e. we can create a button with the hyperlink /species/iguana and this will
# allow the user to view the information about the species
# please be aware the page expects a .jpg at:
# /static/images/species_database/{{photoid}}.jpg but this will be generated automatically
# so long as you use the species_portal or species editor pages I created - CS
@page.route("/articles/<article_id>")
def data(article_id):
database_entry = get_article_by_id(article_id)
if database_entry is None:
raise TypeError(f"No species named '{species_english}' found in the database.")
return render_template(
"library/article.jinja",
article_id =database_entry["article_id" ].capitalize(),
title =database_entry["title" ].capitalize(),
subtitle =database_entry["subtitle" ],
main_text =database_entry["main_text" ].capitalize(),
author =database_entry["author" ],
publish_date=database_entry["publish_date" ])
@page.route("/species/image/<photoid>")
def image(photoid):
return send_from_directory("database/images", photoid)
+30
View File
@@ -0,0 +1,30 @@
from flask import render_template, Blueprint, request
import configparser
from database.db_commands import get_all_articles, search_articles, get_species_by_name
from utilities.featured_species import featured_species_function
config = configparser.ConfigParser()
page = Blueprint("articles", __name__, url_prefix="/articles")
# article library page
@page.route("")
def all_species():
article_list = get_all_articles()
article_list = sorted(article_list, key=lambda sp: sp["title"])
for sp in article_list:
print(sp['title'])
return render_template("library/library.jinja", articles=article_list)
# search page
@page.route("/search")
def search():
query = request.args.get("search-query")
results = search_articles(query)
print(results)
return render_template("/library/article_search.jinja", results=results, query=query)
+1 -1
View File
@@ -73,7 +73,7 @@
Create a free account to track species, contribute to our database, and connect with the conservation community.
</p>
<div class="homepage-buttons">
{{ button(url='/accounts/user_registration', button_text='Create an Account', extra_classes='homepage-btn') }}
{{ button(url='/register', button_text='Create an Account', extra_classes='homepage-btn') }}
</div>
</div>
</section>
+18 -2
View File
@@ -1,6 +1,6 @@
{% macro display_all_items(items)%}
{% macro display_all_species(items)%}
{# Displays all species in the provided 'items' array #}
{# Used in the species database and species results pages #}
{# Used in the species database and search species results pages #}
<section class="species-grid">
{% for item in items %}
<a href="/species/{{ item['species_english'] }}" class="container-lite">
@@ -15,4 +15,20 @@
{% endfor %}
</section>
{% endmacro %}
{% macro display_all_articles(items)%}
{# Displays all articles in the provided 'items' array #}
{# Used in the article library and article search results pages #}
<section class="species-grid">
{% for item in items %}
<a href="/articles/{{ item['article_id'] }}" class="container-lite">
<h3 class="plain-white-text">{{ item['title'] }}</h3>
<p style="color: var(--text)">
Main category: {{ item['author'] }}
Date published: {{ item["publish_date"] }}
</p>
</a>
{% endfor %}
</section>
{% endmacro %}
+23
View File
@@ -0,0 +1,23 @@
{% extends "base.jinja" %}
{% block title %}{{ english_name }} {% endblock %}
{% block head %}
{% endblock %}
{% block content %}
{% from 'button.jinja' import button %}
<div class="species-layout">
<section id="summary" style="padding: 10px 20px; text-align: center; margin-top:1rem" class="container">
<h1>{{ title }}</h1>
<h2><em>{{ subtitle }}</em></h2>
<p>Category: {{author}}</p>
<p>Category: {{publish_date}}</p>
</section>
<section id="info" style="padding: 10px 20px; text-align: center;" class="container">
<p>{{ main_text }}</p>
</section>
</div>
{# this button should only be visible to certain account types #}
{# <div style="text-align: right;">
{{ button(url='/species/editor/'+species_id, button_text='Edit Species') }}
</div> #}
{% endblock %}
+15
View File
@@ -0,0 +1,15 @@
{% extends "base.jinja" %}
{% block title %}Species Database{% endblock %}
{% block head %}
{% endblock %}
{% block content %}
{% from 'button.jinja' import button %}
{% from 'display_items.jinja' import display_all_articles %}
{% from 'search_bar.jinja' import search_bar%}
<section class="title">
Article Library
</section>
{# All Species #}
{{search_bar("/articles/search", query)}}
{{display_all_articles(results)}}
{% endblock %}
+16
View File
@@ -0,0 +1,16 @@
{% extends "base.jinja" %}
{% block title %}Species Database{% endblock %}
{% block head %}
{% endblock %}
{% block content %}
{% from 'button.jinja' import button %}
{% from 'display_items.jinja' import display_all_articles %}
{% from 'search_bar.jinja' import search_bar%}
<section class="title">
Article Library
</section>
{# All Articles #}
{{search_bar("/articles/search", "")}}
<h2 style="text-align: center; margin-top: 30px;">All Articles</h2>
{{display_all_articles(articles)}}
{% endblock %}
+2 -2
View File
@@ -5,7 +5,7 @@
{% block content %}
{% from 'button.jinja' import button %}
{% from 'featured_species.jinja' import featured_species_section %}
{% from 'display_items.jinja' import display_all_items %}
{% from 'display_items.jinja' import display_all_species %}
{% from 'search_bar.jinja' import search_bar%}
<section class="title">
Species Database
@@ -16,5 +16,5 @@ Species Database
{# All Species #}
{{search_bar("/species/search", "")}}
<h2 style="text-align: center; margin-top: 30px;">All Species</h2>
{{display_all_items(species)}}
{{display_all_species(species)}}
{% endblock %}
+2 -2
View File
@@ -4,12 +4,12 @@
{% endblock %}
{% block content %}
{% from 'button.jinja' import button %}
{% from 'display_items.jinja' import display_all_items %}
{% from 'display_items.jinja' import display_all_species %}
{% from 'search_bar.jinja' import search_bar%}
<section class="title">
Species Database
</section>
{# All Species #}
{{search_bar("/species/search", query)}}
{{display_all_items(results)}}
{{display_all_species(results)}}
{% endblock %}