From 32cfdeded0dca3935abff3ac8c25f04dedae7a8c Mon Sep 17 00:00:00 2001 From: Zdenek Kasner Date: Thu, 14 Nov 2024 12:39:37 +0000 Subject: [PATCH 1/3] Hotfix for viewing quintd1-human campaign --- factgenie/analysis.py | 45 ++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/factgenie/analysis.py b/factgenie/analysis.py index 5ca7f5dd..f5760258 100644 --- a/factgenie/analysis.py +++ b/factgenie/analysis.py @@ -14,6 +14,7 @@ from slugify import slugify import logging import coloredlogs +import traceback import factgenie.workflows as workflows from factgenie import CAMPAIGN_DIR @@ -225,26 +226,30 @@ def compute_extra_fields_stats(example_index): # compute aggregate statistics for flags, options and text_fields (aggregates of value counts for each label) extra_fields_stats = {} - for field in ["flags", "options", "text_fields"]: - # each of `example_index[field]` is a list of dicts - # each dict contains `label` and `value` keys - # we want to count the number of occurrences of each `value` for each unique `label` - # and then assign the dictionary with these counts to extra_fields_stats[label] - - # find unique labels - labels = set() - for example in example_index[field]: - for d in example: - labels.add(d["label"]) - - # create a dictionary for each label - for label in labels: - extra_fields_stats[label] = defaultdict(int) - - # count the occurrences of each value for each label - for example in example_index[field]: - for d in example: - extra_fields_stats[d["label"]][d["value"]] += 1 + try: + for field in ["flags", "options", "text_fields"]: + # each of `example_index[field]` is a list of dicts + # each dict contains `label` and `value` keys + # we want to count the number of occurrences of each `value` for each unique `label` + # and then assign the dictionary with these counts to extra_fields_stats[label] + + # find unique labels + labels = set() + for example in example_index[field]: + for d in example: + labels.add(d["label"]) + + # create a dictionary for each label + for label in labels: + extra_fields_stats[label] = defaultdict(int) + + # count the occurrences of each value for each label + for example in example_index[field]: + for d in example: + extra_fields_stats[d["label"]][d["value"]] += 1 + except Exception as e: + logger.error(f"Error while computing extra fields statistics: {e}") + traceback.print_exc() return extra_fields_stats From 4fe99766f4381a1f0021ec5de00dc744b4dbdea5 Mon Sep 17 00:00:00 2001 From: Zdenek Kasner Date: Thu, 14 Nov 2024 12:41:03 +0000 Subject: [PATCH 2/3] Add public mode: an option to view Browse and Analyze pages while locking the rest --- factgenie/app.py | 20 +++++++++++++++++++- factgenie/bin/run.py | 2 +- factgenie/config/config_TEMPLATE.yml | 15 +++++++++++---- factgenie/static/css/custom.css | 14 ++++++++++++++ factgenie/static/js/config.js | 1 + factgenie/templates/pages/app_config.html | 11 +++++++++++ factgenie/templates/pages/index.html | 8 ++++---- 7 files changed, 61 insertions(+), 10 deletions(-) diff --git a/factgenie/app.py b/factgenie/app.py index f324ef3f..1ca39df7 100644 --- a/factgenie/app.py +++ b/factgenie/app.py @@ -94,9 +94,23 @@ def prettify_json(value): # Decorators # ----------------- # Very simple decorator to protect routes + +def is_view_allowed(path): + # if view pages are locked, do not allow any page + if app.config["login"].get("lock_view_pages", True): + return False + + # otherwise allow to view the main page, browse and analyze pages + if path == "/" or path.startswith("/browse") or path.startswith("/analyze"): + return True + + # and lock the rest of pages + return False + def login_required(f): def wrapper(*args, **kwargs): - if app.config["login"]["active"]: + # the browse/analyze pages are allowed without login + if app.config["login"]["active"] and not is_view_allowed(request.path): auth = request.cookies.get("auth") if not auth: return redirect(app.config["host_prefix"] + "/login") @@ -117,9 +131,13 @@ def wrapper(*args, **kwargs): @login_required def index(): logger.info(f"Main page loaded") + + dim_unaccessible_pages = app.config["login"]["active"] and app.config["login"].get("lock_view_pages") == False + return render_template( "pages/index.html", host_prefix=app.config["host_prefix"], + dim_unaccessible_pages=dim_unaccessible_pages, ) diff --git a/factgenie/bin/run.py b/factgenie/bin/run.py index af275e13..4e7f93bc 100644 --- a/factgenie/bin/run.py +++ b/factgenie/bin/run.py @@ -312,9 +312,9 @@ def create_app(**kwargs): logger=logger, fmt="%(asctime)s %(levelname)s %(filename)s:%(lineno)d %(message)s", ) - config["host_prefix"] = os.getenv("FACTGENIE_HOST_PREFIX", config["host_prefix"]) config["login"]["active"] = os.getenv("FACTGENIE_LOGIN_ACTIVE", config["login"]["active"]) + config["login"]["lock_view_pages"] = os.getenv("FACTGENIE_LOCK_VIEW_PAGES", config["login"].get("lock_view_pages", True)) config["login"]["username"] = os.getenv("FACTGENIE_LOGIN_USERNAME", config["login"]["username"]) config["login"]["password"] = os.getenv("FACTGENIE_LOGIN_PASSWORD", config["login"]["password"]) diff --git a/factgenie/config/config_TEMPLATE.yml b/factgenie/config/config_TEMPLATE.yml index 19ef640d..f89d15ef 100644 --- a/factgenie/config/config_TEMPLATE.yml +++ b/factgenie/config/config_TEMPLATE.yml @@ -1,9 +1,16 @@ --- -host_prefix: "" -logging: - level: INFO - flask_debug: false login: + # require user login for all pages except the page for human annotators active: false + # if set to `false`, the Browse and Analyze pages will not require login even when login is active (useful for publishing results) + lock_view_pages: true + # !!! change the default values !!! username: admin password: factgenie +logging: + # accepts values from the logging module: https://docs.python.org/3/library/logging.html#logging-levels + level: INFO + # printing extra Flask debug logs + flask_debug: false +# set e.g. to "/demo/factgenie" if your app is running behind a reverse proxy on https://your-server.com/demo/factgenie +host_prefix: "" diff --git a/factgenie/static/css/custom.css b/factgenie/static/css/custom.css index 7d18d977..4636bb60 100755 --- a/factgenie/static/css/custom.css +++ b/factgenie/static/css/custom.css @@ -996,4 +996,18 @@ a:hover { .panel-50 { min-width: 900px; +} + +.locked-grey { + background-color: #f3f3f3; + border: 1px solid #dcdcdc; + color: #666666; +} + +.locked-grey a img { + filter: opacity(0.5); +} + +.locked-grey h5 { + filter: opacity(0.5); } \ No newline at end of file diff --git a/factgenie/static/js/config.js b/factgenie/static/js/config.js index 78c28ab5..72f29c0c 100644 --- a/factgenie/static/js/config.js +++ b/factgenie/static/js/config.js @@ -8,6 +8,7 @@ function updateConfig() { host_prefix: $('#host_prefix').val(), login: { active: $('#login_active').is(':checked'), + lock_view_pages: $('#lock_view_pages').is(':checked'), username: $('#login_username').val(), password: $('#login_password').val() } diff --git a/factgenie/templates/pages/app_config.html b/factgenie/templates/pages/app_config.html index e28e8c14..a7d996d3 100755 --- a/factgenie/templates/pages/app_config.html +++ b/factgenie/templates/pages/app_config.html @@ -36,6 +36,17 @@
Password protection
app_config.login.active %} checked {% endif %}> +
+ +
+ If disable, the Browse and Analyze pages will not require login even + when login is active. Useful for publishing results collected with factgenie. +
+
+ +
+
diff --git a/factgenie/templates/pages/index.html b/factgenie/templates/pages/index.html index 8cf453a1..715b202b 100755 --- a/factgenie/templates/pages/index.html +++ b/factgenie/templates/pages/index.html @@ -30,7 +30,7 @@
Browse
-
+
-
+
-
+
-
+
From 5e6fadcc2b8588d773913a4b507e417a2aa9d121 Mon Sep 17 00:00:00 2001 From: Zdenek Kasner Date: Mon, 2 Dec 2024 09:39:09 +0100 Subject: [PATCH 3/3] Formatting --- factgenie/app.py | 2 ++ factgenie/bin/run.py | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/factgenie/app.py b/factgenie/app.py index 1ca39df7..fdc92923 100644 --- a/factgenie/app.py +++ b/factgenie/app.py @@ -95,6 +95,7 @@ def prettify_json(value): # ----------------- # Very simple decorator to protect routes + def is_view_allowed(path): # if view pages are locked, do not allow any page if app.config["login"].get("lock_view_pages", True): @@ -107,6 +108,7 @@ def is_view_allowed(path): # and lock the rest of pages return False + def login_required(f): def wrapper(*args, **kwargs): # the browse/analyze pages are allowed without login diff --git a/factgenie/bin/run.py b/factgenie/bin/run.py index 4e7f93bc..6936519e 100644 --- a/factgenie/bin/run.py +++ b/factgenie/bin/run.py @@ -314,7 +314,9 @@ def create_app(**kwargs): ) config["host_prefix"] = os.getenv("FACTGENIE_HOST_PREFIX", config["host_prefix"]) config["login"]["active"] = os.getenv("FACTGENIE_LOGIN_ACTIVE", config["login"]["active"]) - config["login"]["lock_view_pages"] = os.getenv("FACTGENIE_LOCK_VIEW_PAGES", config["login"].get("lock_view_pages", True)) + config["login"]["lock_view_pages"] = os.getenv( + "FACTGENIE_LOCK_VIEW_PAGES", config["login"].get("lock_view_pages", True) + ) config["login"]["username"] = os.getenv("FACTGENIE_LOGIN_USERNAME", config["login"]["username"]) config["login"]["password"] = os.getenv("FACTGENIE_LOGIN_PASSWORD", config["login"]["password"])