Ajax search
This commit is contained in:
@ -1,7 +1,7 @@
|
|||||||
FROM python:3.9-alpine
|
FROM python:3.9-alpine
|
||||||
RUN pip install --no-cache-dir -U setuptools pip wheel && pip install --no-cache-dir Flask icalendar gunicorn
|
RUN pip install --no-cache-dir Flask icalendar gunicorn Unidecode
|
||||||
COPY . /app
|
COPY . /app
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
CMD ["gunicorn", "--workers=2", "--access-logfile", "-", "--log-level", "warning", "-b", "0.0.0.0:5000", "app:app"]
|
CMD ["gunicorn", "--workers=2", "--access-logfile", "-", "--log-level", "debug", "-b", "0.0.0.0:5000", "app:app"]
|
||||||
#CMD python app.py
|
#CMD python app.py
|
||||||
|
56
app.py
56
app.py
@ -1,22 +1,23 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import json
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
|
import logging
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from typing import Iterable, Mapping
|
from typing import Iterable, Mapping
|
||||||
|
|
||||||
from flask import Flask, request, render_template, send_file
|
from flask import Flask, request, render_template, send_file, jsonify
|
||||||
from icalendar import Calendar, Event, Alarm
|
from icalendar import Calendar, Event, Alarm
|
||||||
|
from unidecode import unidecode
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
# Source JSON created from http://vvc.gov.lv/export/sites/default/files/paplasinatais_saraksts.pdf
|
# Source JSON created from http://vvc.gov.lv/export/sites/default/files/paplasinatais_saraksts.pdf
|
||||||
|
|
||||||
|
|
||||||
def generate_ical_for_mapping(cal: Mapping[datetime.date, Iterable[str]]) -> BytesIO:
|
def generate_ical_for_mapping(cal: Mapping[datetime.date, Iterable[str]]) -> BytesIO:
|
||||||
ical = Calendar()
|
ical = Calendar()
|
||||||
ical['VERSION'] = "2.0"
|
ical["VERSION"] = "2.0"
|
||||||
ical['PRODID'] = "NameDays"
|
ical["PRODID"] = "NameDays"
|
||||||
for date, names in sorted(cal.items(), key=lambda x: x[0]):
|
for date, names in sorted(cal.items(), key=lambda x: x[0]):
|
||||||
ev = Event()
|
ev = Event()
|
||||||
ev.add("SUMMARY", ", ".join(sorted(names)))
|
ev.add("SUMMARY", ", ".join(sorted(names)))
|
||||||
@ -35,30 +36,47 @@ def generate_ical_for_mapping(cal: Mapping[datetime.date, Iterable[str]]) -> Byt
|
|||||||
return BytesIO(ical.to_ical(True))
|
return BytesIO(ical.to_ical(True))
|
||||||
|
|
||||||
|
|
||||||
@app.route('/', methods=["POST", "GET"])
|
@app.route("/", methods=["POST", "GET"])
|
||||||
def calendar():
|
def calendar():
|
||||||
with open("vardadienas.json") as f:
|
|
||||||
vdienas = json.load(f)
|
|
||||||
names_dict = {
|
|
||||||
f"{int(month):02}_{int(day):02}_{name}": name
|
|
||||||
for month, month_data in vdienas.items()
|
|
||||||
for day, day_data in month_data.items()
|
|
||||||
for names in day_data.values()
|
|
||||||
for name in names
|
|
||||||
}
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
|
with open("vardadienas.json") as f:
|
||||||
|
vdienas = json.load(f)
|
||||||
cal = defaultdict(list)
|
cal = defaultdict(list)
|
||||||
for selected_name in request.form.getlist("words"):
|
for selected_name in request.form.getlist("words"):
|
||||||
if selected_name in names_dict:
|
month, day, name = selected_name.split("__")
|
||||||
month, day, name = selected_name.split("_")
|
vdmd = vdienas[str(int(month))][str(int(day))]
|
||||||
|
if name in vdmd["normal"] or name in vdmd["special"]:
|
||||||
date = datetime.date(2000, int(month), int(day))
|
date = datetime.date(2000, int(month), int(day))
|
||||||
cal[date].append(name)
|
cal[date].append(name)
|
||||||
if cal:
|
if cal:
|
||||||
name = f"{uuid.uuid4().hex}.ics"
|
name = f"{uuid.uuid4().hex}.ics"
|
||||||
f = generate_ical_for_mapping(cal)
|
f = generate_ical_for_mapping(cal)
|
||||||
return send_file(f, mimetype="text/calendar", as_attachment=True, download_name=name)
|
return send_file(
|
||||||
words = ((k,v) for k,v in sorted(names_dict.items(), key=lambda x: x[1]))
|
f, mimetype="text/calendar", as_attachment=True, download_name=name
|
||||||
return render_template("namedays.html", words=words)
|
)
|
||||||
|
return render_template("namedays.html")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/search/")
|
||||||
|
def calendar_search():
|
||||||
|
term = request.args.get("term")
|
||||||
|
results = []
|
||||||
|
if term:
|
||||||
|
term = unidecode(term.lower(), errors="preserve")
|
||||||
|
with open("mapping.json") as f:
|
||||||
|
mapping = json.load(f)
|
||||||
|
for kind in ["normal", "special"]:
|
||||||
|
words = {
|
||||||
|
"text": kind.title(),
|
||||||
|
"children": [
|
||||||
|
{"id": key, "text": value}
|
||||||
|
for key, value in mapping[kind].items()
|
||||||
|
if unidecode(value.lower(), errors="preserve").startswith(term)
|
||||||
|
],
|
||||||
|
}
|
||||||
|
if words["children"]:
|
||||||
|
results.append(words)
|
||||||
|
return jsonify({"results": results, "pagination": {"more": False}})
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
1
mapping.json
Normal file
1
mapping.json
Normal file
File diff suppressed because one or more lines are too long
@ -12,32 +12,26 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<h1>Vārdadienu kalendāra ģenerators</h1>
|
<h1>Vārdadienu kalendāra ģenerators</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
{%- if words %}
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="idWordSelect" class="form-label">Atlasi vārdus:</label>
|
<label for="idWordSelect" class="form-label">Atlasi vārdus:</label>
|
||||||
<select name="words" class="form-control js-example-basic-multiple" id="idWordSelect" multiple>
|
<select name="words" class="form-control js-example-basic-multiple" id="idWordSelect" multiple></select>
|
||||||
{%- for key, name in words %}
|
|
||||||
<option value="{{ key }}">{{ name }}</option>
|
|
||||||
{%- endfor -%}
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
<button name="submit" value="submit" class="btn btn-primary">Izveidot</button>
|
<button name="submit" value="submit" class="btn btn-primary">Izveidot</button>
|
||||||
</form>
|
</form>
|
||||||
{% endif -%}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
||||||
<script src="https://code.jquery.com/jquery-3.6.0.slim.min.js"></script>
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('.js-example-basic-multiple').select2();
|
$('.js-example-basic-multiple').select2({minimumInputLength: 2, ajax: {url: "/search/", dataType: "json", delay: 500}});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
Reference in New Issue
Block a user