summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-02-28 00:18:38 +0100
committererdgeist <erdgeist@erdgeist.org>2026-02-28 00:18:38 +0100
commit54e247945dfa3a4bd80f71fce1b506bec12178a9 (patch)
tree6b1a4f9616f4b1bdc7e4486fb5d07dbcc96c3abd
Initial
-rw-r--r--Makefile11
-rwxr-xr-xavon.py91
-rw-r--r--requirements.txt12
-rw-r--r--templates/index.html60
4 files changed, 174 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..484791c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,11 @@
1all: install
2
3run:
4 venv/bin/python avon.py -P 8080 &
5
6venv:
7 python3 -m venv ./venv
8
9install: venv
10 . venv/bin/activate && pip install --upgrade pip
11 . venv/bin/activate && pip install -r requirements.txt
diff --git a/avon.py b/avon.py
new file mode 100755
index 0000000..d47382d
--- /dev/null
+++ b/avon.py
@@ -0,0 +1,91 @@
1#! venv/bin/python
2
3import os
4import sys
5import pprint
6import json
7from flask import Flask,render_template,request
8from argparse import ArgumentParser
9import psycopg2
10
11app = Flask(__name__)
12
13class Convert_jinja_object:
14
15 def __init__(self):
16 self.myvar = 'sample_var'
17
18 def bits_to_years(self, x):
19 year_map = [ "92Q2", "95Q0", "96Q0", "96Q1", "97Q1", "97Q3", "98Q1", "98Q3", "99Q1", "99Q3", "00Q1", "00Q3", "01Q1", "01Q2", "01Q3", "01Q4", "02Q1", "02Q3", "03Q1", "03Q3", "04Q1", "04Q3", "05Q1", "05Q3", "06Q1", "06Q3", "07Q1", "07Q3", "08Q1", "08Q3", "09Q1", "09Q3", "10Q1", "10Q3", "11Q1", "11Q3", "12Q1", "12Q3", "13Q1", "13Q3", "14Q1", "14Q3", "15Q1", "15Q3", "16Q1", "16Q3", "17Q1", "17Q3", "18Q1", "18Q3", "19Q1", "19Q3", "20Q1", "20Q3" ]
20 if x == 0:
21 return '/'
22 years = ''
23 index = 0
24 while x > 0:
25 if index > 0:
26 years = years + ','
27 start_off = (x&-x).bit_length()-1
28 x = ~(x >> start_off)
29 end_off = (x&-x).bit_length()-1
30 x = ~(x >> (end_off + 1))
31 years = years + (year_map[index + start_off])
32 if end_off > 1:
33 years = years + '-' + year_map[index + start_off + end_off - 1]
34 index = index + start_off + end_off + 1
35 return years
36
37@app.route("/", methods=['GET', 'POST'])
38def root():
39 content = request.json
40
41 query = "SELECT DISTINCT ON (id) presence_flag, reverse_flag, biz_flag, zip, nachname, vorname, zusaetze, strasse, hausnummer, verweise, ort, vorwahl, rufnummer, web, email, coords FROM Telefonbuch "
42 where = ""
43 params = []
44 anyjoin = ""
45
46 for i in range(1,5):
47 search = request.form.get("search_{0}_string".format(i))
48 if not search: continue
49 column = request.form.get("search_{0}_column".format(i))
50 operator = request.form.get("search_{0}_operator".format(i))
51 isany = request.form.get("search_{0}_any".format(i))
52
53 if not column in [ 'zip', 'nachname', 'vorname', 'zusaetze', 'strasse', 'hausnummer', 'verweise', 'ort', 'vorwahl', 'rufnummer', 'web', 'email', 'coords' ]: continue
54
55 query = query + "INNER JOIN table_{0} ON Telefonbuch.id = table_{0}.telefonbuch_id ".format(column)
56 if len(where):
57 where = where + "AND "
58 else:
59 where = "WHERE "
60 where = where + "table_{0}.value {1} %s ".format(column, {'equals': '=', 'equalsnot': '<>', 'contains': 'ILIKE', 'containsnot': 'NOT ILIKE', 'beginswith': 'ILIKE'}[operator])
61 if not isany:
62 if len(anyjoin) == 0:
63 anyjoin = "table_" + column
64 else:
65 where = where + "AND " + anyjoin + ".offs = table_" + column + ".offs "
66 if operator in ['contains','containsnot']:
67 search = "%" + search + "%"
68 if operator in ['beginswith']:
69 search = search + "%"
70 params.append(search)
71
72 if len(where) > 0:
73 conn = psycopg2.connect(database="erdgeist", user="postgres", password="", host="127.0.0.1")
74 cur = conn.cursor()
75 print (query + where + ' LIMIT 10000')
76 pprint.pprint( params )
77
78 cur.execute(query + where + ' LIMIT 10000', params)
79 rows = cur.fetchall()
80 else:
81 rows = [[0,0,0,{},{},{},{},{},{},{},{},{},{}]]
82
83 return render_template('index.html', rows=rows, request=request, convert=Convert_jinja_object())
84
85if __name__ == "__main__":
86 parser = ArgumentParser(description="AVON")
87 parser.add_argument("-H", "--host", help="Hostname of the Flask app " + "[default %s]" % "127.0.0.1", default="127.0.0.1")
88 parser.add_argument("-P", "--port", help="Port for the Flask app " + "[default %s]" % "5000", default="5000")
89 args = parser.parse_args()
90
91 app.run(host=args.host, port=int(args.port))
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..7ed34e8
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,12 @@
1certifi==2018.11.29
2chardet==3.0.4
3Click==7.0
4Flask==1.0.2
5idna==2.8
6itsdangerous==1.1.0
7Jinja2==2.10
8MarkupSafe==1.1.1
9psycopg2==2.7.7
10requests==2.21.0
11urllib3==1.24.1
12Werkzeug==0.14.1
diff --git a/templates/index.html b/templates/index.html
new file mode 100644
index 0000000..cf4e616
--- /dev/null
+++ b/templates/index.html
@@ -0,0 +1,60 @@
1<html>
2<title>AVON</title>
3<head>
4<style>
5 td { vertical-align: top; }
6 tr.color_1 { background: #ccc; }
7 table { border: none; }
8</style>
9</head>
10<body>
11<form action="/" METHOD="POST">
12 {%- for field in range(1,5) -%}
13 <div class="search_entry">
14 <select name="search_{{ field }}_column">
15 {% set column_search = request.form.get('search_'+(field|string)+'_string', '') %}
16 {% if column_search | length %}
17 {% set column_val = request.form.get('search_'+(field|string)+'_column') %}
18 {% set operator_val = request.form.get('search_'+(field|string)+'_operator') %}
19 {% set any_val = request.form.get('search_'+(field|string)+'_any') %}
20 {% else %}
21 {% set column_val = ['nachname', 'vorname', 'ort', 'rufnummer'][field-1] %}
22 {% set operator_val = ['equals', 'contains', 'equals', 'contains'][field-1] %}
23 {% set any_val = ['', '', 'on', ''][field-1] %}
24 {% endif %}
25 {%- for column in [ ['vorname', 'Vorname'], ['nachname', 'Nachname'], ['zip', 'PLZ'], ['ort', 'Ort'], ['vorwahl', 'Vorwahl'], ['rufnummer', 'Rufnummer'], ['strasse', 'Straße'], ['hausnummer', 'Hausnummer'], ['zusaetze', 'Zusatz'], ['verweise', 'Verweise / Branche'], ['email', 'E-Mail'], ['web', 'Webseite'] ] -%}
26 <option value="{{ column[0] }}" {%- if column_val== column[0] -%}selected="selected"{%- endif -%}>{{ column[1] }}</option>
27 {%- endfor -%}
28 </select>
29 <select name="search_{{ field }}_operator">
30 {%- for operator in [ [ 'equals', 'equals'], ['beginswith', 'begins with'], ['contains', 'contains' ], ['equalsnot', 'equals not'], ['containsnot', 'contains not'] ] -%}
31 <option value="{{ operator[0] }}" {%- if operator_val == operator[0] -%}selected="selected"{%- endif -%}>{{ operator[1] }}</option>
32 {%- endfor -%}
33 </select>
34 <input type="checkbox" name="search_{{ field }}_any" {%- if any_val == 'on' -%}checked="{%- endif -%}">any</input>
35 <input type="text" name="search_{{ field }}_string" value="{{ request.form.get('search_'+(field|string)+'_string', '') }}">
36 </div>
37 {%- endfor -%}
38 <input type="submit" value="Search">
39</form>
40{% if rows | length > 0 -%}<h3>Found {{ rows | length }} matches.</h3>{% endif %}
41{% set color = { 'value': 0 } %}
42<table>
43 <thead><td>flags</td><td>zip</td></thead>
44{%- for row in rows -%}
45{% set span = row[3:16] | reject("none") | map('length') | max %}
46 {% for r in range (span) %}
47 {% if ( r == 0 ) and ( color.update({ 'value': 1 - color.value }) ) %} {% endif %}
48 <tr class="color_{{ color.value }}">
49 {%- if r == 0 -%}
50 <td rowspan="{{span}}">{{ convert.bits_to_years(row[0]|int) }} : {{ convert.bits_to_years(row[1]|int) }} : {{ convert.bits_to_years(row[2]|int) }}</td>
51 {%- endif -%}
52 {%- for c in range(3, 16) -%}
53 <td>{{ row[c][r] or '' }}</td>
54 {%- endfor -%}
55 </tr>
56 {%- endfor -%}
57{%- endfor -%}
58</table>
59</body>
60</html>