Ajax search

This commit is contained in:
2022-04-04 10:24:04 +03:00
parent e27ee4f342
commit 35841c9f29
4 changed files with 45 additions and 32 deletions

View File

@ -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
View File

@ -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

File diff suppressed because one or more lines are too long

View File

@ -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>