diff --git a/README.md b/README.md index e69de29..ca7509e 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,21 @@ +# CodiMD note overview + + +a searchable list of existing hackmd pads – [https://padlist.wiai.de/](https://padlist.wiai.de/) + + + + +## Testing locally + + +Execute `docker build . --tag codimd; docker run -p 5000:5000 --env TESTING=True codimd` to run the app in testing mode locally. No database credentials are required during testing mode; test data is read from a local file. + +## Open issues + +* make the layout responsive +* either read the DB credentials and URL from the environment or the config file +* load test data from a local file when run in testing mode +* add more/real testing data +* the up and down arrows in the table head fields are not invisible +* add more emojis ヘ( ^o^)ノ\(^_^ ) diff --git a/demo.jpg b/demo.jpg new file mode 100644 index 0000000..8feafcf Binary files /dev/null and b/demo.jpg differ diff --git a/src/main.py b/src/main.py index ce5a1b4..3859c6f 100644 --- a/src/main.py +++ b/src/main.py @@ -1,16 +1,31 @@ import psycopg2 from flask import Flask, render_template import os -import config +from datetime import datetime + app = Flask(__name__) app.debug = True -sql_statement = 'SELECT "id","title","alias","shortid","viewcount","lastchangeAt","permission","content" FROM "Notes" ORDER BY "lastchangeAt" DESC;' +SQL_FETCH_NOTES = 'SELECT "id","title","alias","shortid","viewcount","lastchangeAt","permission","content" FROM "Notes" ORDER BY "lastchangeAt" DESC;' + +# if the environment contains a variable TESTING that is set to "True" then run the application in testing mode +if os.environ.get('TESTING') == "True": + ENV_TESTING = True +else: + ENV_TESTING = False @app.route("/") def main(): + if ENV_TESTING: + return testing() + else: + return production() + + +def production(): + import config DB_HOST = os.environ.get('DB_HOST') DB_NAME = os.environ.get('POSTGRES_DB') DB_USER = os.environ.get('POSTGRES_USER') @@ -20,7 +35,7 @@ def main(): conn = psycopg2.connect(host=DB_HOST, database=DB_NAME, user=DB_USER, password=DB_PASSWORD) cur = conn.cursor() - cur.execute(sql_statement) + cur.execute(SQL_FETCH_NOTES) notes = cur.fetchall() cur.close() conn.close() @@ -34,5 +49,35 @@ def main(): return render_template('index.html') +def testing(): + notes_arr = [] + notes_arr.append( + { + 'id': "SJBWsApiX", + 'title': "None", + 'alias': "35c3", + 'shortid': "SJBWsApiX", + 'viewcount': "0", + 'lastchangeAt': datetime(2013, 10, 31, 18, 23, 29, 227), + 'permission': "freely", + 'content': "xxx" + } + ) + x = { + 'id': "SJBWsApiX", + 'title': "Protokoll für die Fachschaftssitzung vom 6. Februar 2019", + 'alias': "35c3", + 'shortid': "SJBWsApiX", + 'viewcount': "0", + 'lastchangeAt': datetime(2013, 10, 31, 18, 23, 29, 227), + 'permission': "freely" + } + + for _ in range(20): + notes_arr.append(x) + + return render_template('index.html', notes=notes_arr, host="localhost") + + if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) diff --git a/src/static/css/main.css b/src/static/css/main.css deleted file mode 100644 index 3825489..0000000 --- a/src/static/css/main.css +++ /dev/null @@ -1,47 +0,0 @@ -/*.extra-content {*/ -/*display: none;*/ -/*text-decoration: none !important;*/ -/*color: #0b2e13;*/ -/*}*/ - -/*.sortable a {*/ -/*display: inline-block;*/ -/*}*/ - -/*.sortable a:hover .extra-content {*/ -/*display: block;*/ -/*text-decoration: none !important;*/ -/*}*/ - -/*.sortable a:hover .extra-content p {*/ -/*display: block;*/ -/*text-decoration: none !important;*/ -/*}*/ - -.fancy-tooltip { - position: relative; - display: inline-block; -} - -.fancy-tooltip .tooltiptext { - visibility: hidden; - width: 300px; - background-color: #555; - color: #fff; - text-align: center; - border-radius: 6px; - padding: 5px 0; - position: absolute; - z-index: 1; - bottom: -170%; - left: 50%; - margin-left: -60px; - opacity: 0; - transition: opacity 0.3s; - line-height: 1em; -} - -.fancy-tooltip:hover .tooltiptext { - visibility: visible; - opacity: 1; -} \ No newline at end of file diff --git a/src/static/css/style.css b/src/static/css/style.css new file mode 100644 index 0000000..119063a --- /dev/null +++ b/src/static/css/style.css @@ -0,0 +1,11 @@ + +/* Hide stuff from dataTables that we do not neeed */ +.dataTables_length, .dataTables_info, .dataTables_paginate { + visibility: hidden +} + +/* Add some spacing above and below the search field */ +.dataTables_filter { + padding-top: 10%; + padding-bottom: 10%; +} \ No newline at end of file diff --git a/src/static/js/script.js b/src/static/js/script.js new file mode 100644 index 0000000..f4788c7 --- /dev/null +++ b/src/static/js/script.js @@ -0,0 +1,7 @@ + +// make the table a dataTable and show all entries by default +$(document).ready(function () { + $('#example').DataTable({ + "lengthMenu": [[-1], ["All"]] + }); +}); diff --git a/src/static/js/sort.js b/src/static/js/sort.js deleted file mode 100644 index 4dab712..0000000 --- a/src/static/js/sort.js +++ /dev/null @@ -1,61 +0,0 @@ -function updateParent(notesArr) { - let parent = document.getElementById('sortable-wrapper'); - parent.innerHTML = ''; - for (let elem of notesArr) { - parent.appendChild(elem); - } -} - -function convertToArray() { - var notes = document.getElementsByClassName("sortable"); - var notesArr = []; - for (const node of notes) { - notesArr.push(node); - } - return notesArr; -} - -function sortByTitle() { - var sort_by_title = function (a, b) { - let x = a.getElementsByClassName('note-title')[0]; - let y = b.getElementsByClassName('note-title')[0]; - return x.innerHTML.toLowerCase().localeCompare(y.innerHTML.toLowerCase()); - }; - - var notesArr = convertToArray(); - notesArr.sort(sort_by_title); - updateParent(notesArr); -} - -function sortByDate() { - console.log('Sort Date'); - var sort_by_date = function (a, b) { - a = a.getElementsByClassName('note-date')[0]; - b = b.getElementsByClassName('note-date')[0]; - if (a && b) { - a = a.innerHTML.split(' '); - let a_date = a[0].split('.'); - let a_time = a[1].split(':'); - b = b.innerHTML.split('\ '); - let b_date = b[0].split('.'); - let b_time = b[1].split(':'); - let x = new Date(a_date[2], a_date[1], a_date[0], a_time[0], a_time[1]).getTime(); - let y = new Date(b_date[2], b_date[1], b_date[0], b_time[0], b_time[1]).getTime(); - if (x === y) { - return 0; - } else if (x > y) { - return -1; - } else { - return 1; - } - } else { - return 0; - } - - // return x.innerHTML.toLowerCase().localeCompare(y.innerHTML.toLowerCase()); - }; - - var notesArr = convertToArray(); - notesArr.sort(sort_by_date); - updateParent(notesArr); -} diff --git a/src/templates/index.html b/src/templates/index.html index c6da70a..ec1490b 100644 --- a/src/templates/index.html +++ b/src/templates/index.html @@ -1,45 +1,54 @@ +
-| id | +title | +alias | +last change at | +permission | +content | +
|---|---|---|---|---|---|
| {{note['shortid']}} | +{{note['title']}} | +{{note['alias']}} | +{{note['lastchangeAt'].strftime('%d.%m.%Y %H:%M')}} | +{{note['permission']}} | +{%if note['content']%}💬{%else%}❌{%endif%} | +