Author | zPlus <zplus@peers.community> 2023-11-26 07:39:37 |
Committer | zPlus <zplus@peers.community> 2023-11-26 07:39:37 |
Commit | a2024a5 (patch) |
Tree | 779e6e0 |
Parent(s) |
-rwxr-xr-x | app.py | 90 | ||
-rw-r--r-- | pages/library.html | 68 |
index cf85123..9f6b722 | |||
old size: 9K - new size: 12K | |||
@@ -87,6 +87,95 @@ def static(filename): | |||
87 | 87 | ||
88 | 88 | return bottle.static_file(filename, root='./static/') | |
89 | 89 | ||
90 | + | @bottle.route('/library', method=['GET', 'POST'], name='library') | |
91 | + | def library(): | |
92 | + | """ | |
93 | + | Library index | |
94 | + | """ | |
95 | + | ||
96 | + | # Get a list of authors for searching | |
97 | + | authors = query(""" | |
98 | + | PREFIX library: <dokk:library:> | |
99 | + | PREFIX license: <dokk:license:> | |
100 | + | ||
101 | + | SELECT DISTINCT ?name | |
102 | + | WHERE { | |
103 | + | [] library:author ?name | |
104 | + | } | |
105 | + | ORDER BY ?name | |
106 | + | """)['results']['bindings'] | |
107 | + | ||
108 | + | # Get a list of licenses for searching | |
109 | + | licenses = query(""" | |
110 | + | PREFIX library: <dokk:library:> | |
111 | + | PREFIX license: <dokk:license:> | |
112 | + | ||
113 | + | SELECT DISTINCT ?id | |
114 | + | WHERE { | |
115 | + | [] library:license [ | |
116 | + | license:id ?id | |
117 | + | ] . | |
118 | + | } | |
119 | + | ORDER BY ?id | |
120 | + | """)['results']['bindings'] | |
121 | + | ||
122 | + | # Retrieve filters selected by the user | |
123 | + | filters_author = [] | |
124 | + | filters_license = [] | |
125 | + | query_filters = '' | |
126 | + | if request.method == 'POST': | |
127 | + | filters_author = request.forms.getall('author') | |
128 | + | filters_license = request.forms.getall('license') | |
129 | + | ||
130 | + | if len(filters_author) > 0: | |
131 | + | query_filters_author = ','.join([ '"'+i.replace('"', '\\"')+'"' for i in filters_author ]) | |
132 | + | query_filters += f'FILTER(?author IN ({query_filters_author}))' | |
133 | + | ||
134 | + | if len(filters_license) > 0: | |
135 | + | query_filters_license = ','.join([ '"'+i.replace('"', '\\"')+'"' for i in filters_license ]) | |
136 | + | query_filters += f'FILTER(?license_id IN ({query_filters_license}))' | |
137 | + | ||
138 | + | items = query(f""" | |
139 | + | PREFIX library: <dokk:library:> | |
140 | + | PREFIX license: <dokk:license:> | |
141 | + | ||
142 | + | CONSTRUCT {{ | |
143 | + | ?item library:title ?title; | |
144 | + | library:author ?author ; | |
145 | + | library:license ?license . | |
146 | + | ?license license:id ?license_id ; | |
147 | + | license:name ?license_name . | |
148 | + | }} | |
149 | + | WHERE {{ | |
150 | + | ?item library:title ?title ; | |
151 | + | library:author ?author ; | |
152 | + | library:license ?license . | |
153 | + | ||
154 | + | OPTIONAL {{ | |
155 | + | ?license license:id ?license_id_optional ; | |
156 | + | license:name ?license_name_optional . | |
157 | + | }} | |
158 | + | ||
159 | + | BIND(COALESCE(?license_id_optional, SUBSTR(STR(?license), 14)) AS ?license_id) | |
160 | + | BIND(COALESCE(?license_name_optional, SUBSTR(STR(?license), 14)) AS ?license_name) | |
161 | + | ||
162 | + | {query_filters} | |
163 | + | }} | |
164 | + | ORDER BY UCASE(?title) | |
165 | + | """, | |
166 | + | { | |
167 | + | '@context': { | |
168 | + | 'library': 'dokk:library:', | |
169 | + | 'license': 'dokk:license:', | |
170 | + | 'library:author': { '@container': '@set' }, | |
171 | + | 'library:license': { '@container': '@set' } | |
172 | + | }, | |
173 | + | 'library:title': {} | |
174 | + | }) | |
175 | + | ||
176 | + | return template('library.html', authors=authors, licenses=licenses, items=items, | |
177 | + | filters_author=filters_author, filters_license=filters_license) | |
178 | + | ||
90 | 179 | @bottle.get('/library/opds.xml', name='library_opds') | |
91 | 180 | def library_opds(): | |
92 | 181 | """ | |
@@ -329,6 +418,7 @@ def articles(): | |||
329 | 418 | ||
330 | 419 | return template('templates/articles.tpl', pages=pages) | |
331 | 420 | ||
421 | + | # TODO Make this obsolete. Replace with controllers | |
332 | 422 | @bottle.get('/', name='homepage') | |
333 | 423 | @bottle.get('/<page:path>', name='page') | |
334 | 424 | def article(page=''): |
index 9b23f71..570f7d1 | |||
old size: 2K - new size: 2K | |||
@@ -2,43 +2,6 @@ | |||
2 | 2 | ||
3 | 3 | {% block title %}Library{% endblock %} | |
4 | 4 | ||
5 | - | {% set data = query(""" | |
6 | - | PREFIX library: <dokk:library:> | |
7 | - | PREFIX license: <dokk:license:> | |
8 | - | ||
9 | - | CONSTRUCT { | |
10 | - | ?item library:title ?title; | |
11 | - | library:author ?author ; | |
12 | - | library:license ?license . | |
13 | - | ?license license:id ?license_id ; | |
14 | - | license:name ?license_name . | |
15 | - | } | |
16 | - | WHERE { | |
17 | - | ?item library:title ?title ; | |
18 | - | library:author ?author ; | |
19 | - | library:license ?license . | |
20 | - | ||
21 | - | OPTIONAL { | |
22 | - | ?license license:id ?license_id_optional ; | |
23 | - | license:name ?license_name_optional . | |
24 | - | } | |
25 | - | ||
26 | - | BIND(COALESCE(?license_id_optional, SUBSTR(STR(?license), 14)) AS ?license_id) | |
27 | - | BIND(COALESCE(?license_name_optional, SUBSTR(STR(?license), 14)) AS ?license_name) | |
28 | - | } | |
29 | - | ORDER BY UCASE(?title) | |
30 | - | """, | |
31 | - | { | |
32 | - | '@context': { | |
33 | - | 'library': 'dokk:library:', | |
34 | - | 'license': 'dokk:license:', | |
35 | - | 'library:author': { '@container': '@set' }, | |
36 | - | 'library:license': { '@container': '@set' } | |
37 | - | }, | |
38 | - | 'library:title': {} | |
39 | - | }) | |
40 | - | %} | |
41 | - | ||
42 | 5 | {% block body %} | |
43 | 6 | ||
44 | 7 | <div class="library"> | |
@@ -46,7 +9,36 @@ | |||
46 | 9 | <b>The library is also available via OPDS. Add this link to your OPDS client: https://dokk.org/library/opds.xml</b> | |
47 | 10 | <br /><br /><br /> | |
48 | 11 | ||
49 | - | {% for item in data["@graph"]|sort(attribute="library:title") %} | |
12 | + | <details> | |
13 | + | <summary>Filters</summary> | |
14 | + | ||
15 | + | <form action="" method="post"> | |
16 | + | <br /> | |
17 | + | ||
18 | + | Author: | |
19 | + | <br /> | |
20 | + | <select name="author" multiple size=10> | |
21 | + | {% for author in authors %} | |
22 | + | <option value="{{ author['name']['value'] }}" {{ 'selected' if author['name']['value'] in filters_author }}>{{ author['name']['value'] }}</option> | |
23 | + | {% endfor %} | |
24 | + | </select> | |
25 | + | ||
26 | + | <br /><br /> | |
27 | + | ||
28 | + | License: | |
29 | + | <br /> | |
30 | + | <select name="license" multiple size=10> | |
31 | + | {% for license in licenses %} | |
32 | + | <option value="{{ license['id']['value'] }}" {{ 'selected' if license['id']['value'] in filters_license }}>{{ license['id']['value'] }}</option> | |
33 | + | {% endfor %} | |
34 | + | </select> | |
35 | + | ||
36 | + | <br /><br /> | |
37 | + | <input type="submit" value="Search" /> | |
38 | + | </form> | |
39 | + | </details> | |
40 | + | ||
41 | + | {% for item in items["@graph"]|sort(attribute="library:title") %} | |
50 | 42 | <p> | |
51 | 43 | <div> | |
52 | 44 | <a href="/library/{{ item['@id'][8:] }}">{{ item['library:title'] }}</a> |