Compare commits
7 commits
6a0e76440a
...
59878c16a7
Author | SHA1 | Date | |
---|---|---|---|
Edward Betts | 59878c16a7 | ||
Edward Betts | c4eec7bb73 | ||
Edward Betts | f3f570063f | ||
Edward Betts | e6647a6425 | ||
Edward Betts | 2cf5dbb22e | ||
Edward Betts | a7e2d17063 | ||
Edward Betts | 0e37348e14 |
|
@ -5,9 +5,8 @@ import typing
|
||||||
|
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
import sqlalchemy.orm.decl_api
|
import sqlalchemy.orm.decl_api
|
||||||
from sqlalchemy import Index, func, text
|
from sqlalchemy import func
|
||||||
from sqlalchemy.dialects import postgresql
|
from sqlalchemy.dialects import postgresql
|
||||||
from sqlalchemy.dialects.postgresql import TSVECTOR
|
|
||||||
from sqlalchemy.ext.associationproxy import association_proxy
|
from sqlalchemy.ext.associationproxy import association_proxy
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
from sqlalchemy.ext.orderinglist import ordering_list
|
from sqlalchemy.ext.orderinglist import ordering_list
|
||||||
|
@ -172,22 +171,6 @@ class Event(TimeStampedModel):
|
||||||
event_type = Column(String)
|
event_type = Column(String)
|
||||||
url = Column(String)
|
url = Column(String)
|
||||||
cancelled = Column(Boolean)
|
cancelled = Column(Boolean)
|
||||||
search_vector = Column(TSVECTOR)
|
|
||||||
|
|
||||||
trigger = text(
|
|
||||||
"""
|
|
||||||
CREATE TRIGGER event_vector_update BEFORE INSERT OR UPDATE
|
|
||||||
ON event FOR EACH ROW EXECUTE FUNCTION
|
|
||||||
tsvector_update_trigger(search_vector, 'pg_catalog.english', title, abstract, description);
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
Index(
|
|
||||||
"event_search_vector_idx",
|
|
||||||
search_vector,
|
|
||||||
postgresql_using="gin",
|
|
||||||
postgresql_ops={"abstract_search_vector": "gin_trgm_ops"},
|
|
||||||
)
|
|
||||||
|
|
||||||
conference = relationship("Conference", back_populates="events")
|
conference = relationship("Conference", back_populates="events")
|
||||||
|
|
||||||
|
|
4
main.py
4
main.py
|
@ -182,6 +182,8 @@ def search_people() -> str:
|
||||||
|
|
||||||
@app.route("/merge", methods=["GET", "POST"])
|
@app.route("/merge", methods=["GET", "POST"])
|
||||||
def merge() -> str | Response:
|
def merge() -> str | Response:
|
||||||
|
assert app.config["ADMIN_MODE"]
|
||||||
|
|
||||||
if flask.request.method == "POST":
|
if flask.request.method == "POST":
|
||||||
search_for = flask.request.form["q"]
|
search_for = flask.request.form["q"]
|
||||||
|
|
||||||
|
@ -407,6 +409,8 @@ def search_everything() -> str:
|
||||||
|
|
||||||
@app.route("/person/<int:person_id>/delete", methods=["POST"])
|
@app.route("/person/<int:person_id>/delete", methods=["POST"])
|
||||||
def delete_person(person_id: int) -> str | Response:
|
def delete_person(person_id: int) -> str | Response:
|
||||||
|
assert app.config["ADMIN_MODE"]
|
||||||
|
|
||||||
item = model.Person.query.get(person_id)
|
item = model.Person.query.get(person_id)
|
||||||
|
|
||||||
for cp in item.conferences_association:
|
for cp in item.conferences_association:
|
||||||
|
|
|
@ -2,21 +2,10 @@
|
||||||
|
|
||||||
{% block title %}Conference archive{% endblock %}
|
{% block title %}Conference archive{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
<div>
|
||||||
<div class="row">
|
|
||||||
<h1>Conference archive</h1>
|
<h1>Conference archive</h1>
|
||||||
|
|
||||||
{#
|
|
||||||
<form action="{{ url_for("search_people") }}">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="q" class="form-label">speaker name</label>
|
|
||||||
<input type="text" class="form-control" name="q" id="q">
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary">Search</button>
|
|
||||||
</form>
|
|
||||||
#}
|
|
||||||
|
|
||||||
<div style="margin-bottom:1rem">
|
<div style="margin-bottom:1rem">
|
||||||
👥
|
👥
|
||||||
{{ "{:,d}".format(count.conference) }} conferences<br/>
|
{{ "{:,d}".format(count.conference) }} conferences<br/>
|
||||||
|
@ -25,8 +14,7 @@
|
||||||
📍
|
📍
|
||||||
{{ "{:,d}".format(count.venue) }} venues<br/>
|
{{ "{:,d}".format(count.venue) }} venues<br/>
|
||||||
🎤
|
🎤
|
||||||
{{ "{:,d}".format(count.event) }} talks -
|
{{ "{:,d}".format(count.event) }} talks<br/>
|
||||||
<a href="{{ url_for("events_page") }}">most common titles</a><br/>
|
|
||||||
👤
|
👤
|
||||||
{{ "{:,d}".format(count.person) }} speakers
|
{{ "{:,d}".format(count.person) }} speakers
|
||||||
<a href="{{ url_for("top_speakers_page") }}">top speakers</a><br/>
|
<a href="{{ url_for("top_speakers_page") }}">top speakers</a><br/>
|
||||||
|
@ -66,10 +54,6 @@
|
||||||
{{ item.people_detail.count() }} speakers<br/>
|
{{ item.people_detail.count() }} speakers<br/>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<p>
|
<p>
|
||||||
<form action="{{ url_for("search_people") }}">
|
<form action="{{ url_for("search_people") }}">
|
||||||
<a href="{{ url_for("index") }}">home</a>
|
<a href="{{ url_for("index") }}">conferences</a>
|
||||||
| <a href="{{ url_for("events_page") }}">events</a>
|
|
||||||
| <a href="{{ url_for("top_speakers_page") }}">speakers</a>
|
| <a href="{{ url_for("top_speakers_page") }}">speakers</a>
|
||||||
|
|
||||||
<input type="text" class="form-control" placeholder="speaker name" name="q" id="q">
|
<input type="text" class="form-control" placeholder="speaker name" name="q" id="q">
|
||||||
|
|
|
@ -21,8 +21,8 @@
|
||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
<div>
|
||||||
<div class="row">
|
<div>
|
||||||
|
|
||||||
{% set photo = item.photo_filename() %}
|
{% set photo = item.photo_filename() %}
|
||||||
{% if photo %}
|
{% if photo %}
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
{% if config.ADMIN_MODE %}
|
||||||
{% set search_for = item.name + ' ' + " haswbstatement:P31=Q5" %}
|
{% set search_for = item.name + ' ' + " haswbstatement:P31=Q5" %}
|
||||||
<p><a href="https://www.wikidata.org/w/index.php?search={{ search_for | urlencode }}&title=Special%3ASearch&ns0=1&ns120=1">Search for {{ item.name }} on Wikidata</a></p>
|
<p><a href="https://www.wikidata.org/w/index.php?search={{ search_for | urlencode }}&title=Special%3ASearch&ns0=1&ns120=1">Search for {{ item.name }} on Wikidata</a></p>
|
||||||
|
|
||||||
|
@ -80,6 +80,7 @@
|
||||||
<p>No similar names found on Wikidata</p>
|
<p>No similar names found on Wikidata</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% set bio_source = item.bio_source() %}
|
{% set bio_source = item.bio_source() %}
|
||||||
{% if bio_source %}
|
{% if bio_source %}
|
||||||
|
|
|
@ -17,9 +17,12 @@
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Found {{ q.count() }} people matching '{{ search_for }}'
|
{% set count = q.count() %}
|
||||||
|
Found {{ count }} people matching '{{ search_for }}'
|
||||||
|
|
||||||
|
{% if config.ADMIN_MODE and count %}
|
||||||
<a href="{{ url_for("merge", q=search_for) }}">merge</a>
|
<a href="{{ url_for("merge", q=search_for) }}">merge</a>
|
||||||
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
|
|
@ -1,40 +1,34 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block style %}
|
{% block style %}
|
||||||
<script src="{{ url_for("static", filename="leader-line.min.js") }}"></script>
|
|
||||||
<style>
|
<style>
|
||||||
.right-images {
|
.person {
|
||||||
position: absolute;
|
display: flex;
|
||||||
right: -280px;
|
align-items: top;
|
||||||
top: 0;
|
margin-bottom: 10px;
|
||||||
width: 120px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.left-images {
|
.info {
|
||||||
position: absolute;
|
flex: 1; /* Allow text to take remaining space */
|
||||||
right: -140px;
|
padding-right: 10px; /* Add spacing between text and image */
|
||||||
top: 0;
|
|
||||||
width: 120px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
img.photo {
|
||||||
|
max-width: 120px; /* Set max width for images */
|
||||||
.image {
|
height: auto; /* Maintain image aspect ratio */
|
||||||
max-width: 100%;
|
|
||||||
}
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
.container {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% set show_images = True %}
|
{% set show_images = False %}
|
||||||
|
|
||||||
{% block title %}Conference archive{% endblock %}
|
{% block title %}Conference archive{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container">
|
<div>
|
||||||
|
|
||||||
{% if show_images %}
|
{% if show_images %}
|
||||||
|
|
||||||
|
@ -88,65 +82,22 @@
|
||||||
{% if loop.first or loop.previtem[1] != count %}
|
{% if loop.first or loop.previtem[1] != count %}
|
||||||
<h4>{{ count }} conferences</h4>
|
<h4>{{ count }} conferences</h4>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div>
|
<div class="person">
|
||||||
<span id="person-{{ person.id }}">
|
{% set photo = person.photo_filename() %}
|
||||||
|
<span class="info" id="person-{{ person.id }}">
|
||||||
👤
|
👤
|
||||||
<a href="{{ url_for("person", person_id=person.id) }}">{{ person.name }}</a>
|
<a href="{{ url_for("person", person_id=person.id) }}">{{ person.name }}</a><br>
|
||||||
({{ count }} conferences, {{ person.event_count }} talks)
|
({{ count }} conferences, {{ person.event_count }} talks)
|
||||||
{% if person.photo_filename() %}📷{% endif %}
|
{% if person.photo_filename() %}📷{% endif %}
|
||||||
{% if person.wikidata_qid %}
|
{% if person.wikidata_qid %}
|
||||||
<a href="https://www.wikidata.org/wiki/{{ person.wikidata_qid }}">Wikidata</a>
|
<a href="https://www.wikidata.org/wiki/{{ person.wikidata_qid }}">Wikidata</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
|
{% if photo %}
|
||||||
|
<img class="photo" src="{{ url_for("static", filename=photo) }}" alt="{{ person.name }}">
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block script %}
|
|
||||||
{% if show_images %}
|
|
||||||
<script>
|
|
||||||
{# var person_ids = {{ photo_person_ids | tojson }}; #}
|
|
||||||
var left = {{ left | tojson }};
|
|
||||||
var right = {{ right | tojson }};
|
|
||||||
var lines = {};
|
|
||||||
|
|
||||||
window.addEventListener('load', function() {
|
|
||||||
|
|
||||||
for(var i =0; i < left.length; i++) {
|
|
||||||
var id = left[i];
|
|
||||||
var person = document.getElementById('person-' + id);
|
|
||||||
var image = document.getElementById('image-' + id);
|
|
||||||
|
|
||||||
var line = new LeaderLine(LeaderLine.mouseHoverAnchor(person, 'draw'), image);
|
|
||||||
line.setOptions({startSocket: 'right', endSocket: 'left', path: 'fluid'});
|
|
||||||
|
|
||||||
var line2 = new LeaderLine(LeaderLine.mouseHoverAnchor(image, 'draw'), person);
|
|
||||||
line2.setOptions({startSocket: 'left', endSocket: 'right', path: 'fluid'});
|
|
||||||
|
|
||||||
|
|
||||||
// lines[id] = line;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(var i =0; i < right.length; i++) {
|
|
||||||
var id = right[i];
|
|
||||||
var person = document.getElementById('person-' + id);
|
|
||||||
var image = document.getElementById('image-' + id);
|
|
||||||
|
|
||||||
var line = new LeaderLine(LeaderLine.mouseHoverAnchor(person, 'draw'), image);
|
|
||||||
line.setOptions({startSocket: 'right', endSocket: 'left', path: 'fluid'});
|
|
||||||
|
|
||||||
var line2 = new LeaderLine(LeaderLine.mouseHoverAnchor(image, 'draw'), person);
|
|
||||||
line2.setOptions({startSocket: 'left', endSocket: 'right', path: 'fluid'});
|
|
||||||
|
|
||||||
// lines[id] = line;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
Loading…
Reference in a new issue