From a3d3ca7a7bb92f81fbe70972014e2522fa45364c Mon Sep 17 00:00:00 2001
From: Johannes Brachem <37882800+jobrachem@users.noreply.github.com>
Date: Wed, 16 Feb 2022 11:53:40 +0100
Subject: [PATCH 01/13] allow users to remove documents
Applies only to their own collections
---
src/mortimer/models.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/mortimer/models.py b/src/mortimer/models.py
index 58b71f1..6667ba9 100644
--- a/src/mortimer/models.py
+++ b/src/mortimer/models.py
@@ -89,7 +89,7 @@ def _prepare_db_role_privileges(self):
c_unlinked = {**res, **{"collection": self.alfred_col_unlinked}}
c_misc = {**res, **{"collection": self.alfred_col_misc}}
- act = ["find", "insert", "update"]
+ act = ["find", "insert", "update", "remove"]
priv = [{"resource": res_dict, "actions": act} for res_dict in [c_exp, c_unlinked, c_misc]]
return priv
From 601feace442217343aa000a667ff22cce78ad525 Mon Sep 17 00:00:00 2001
From: Johannes Brachem <37882800+jobrachem@users.noreply.github.com>
Date: Wed, 16 Feb 2022 11:54:31 +0100
Subject: [PATCH 02/13] Update url-jumping mechanism
Brings url-jumping up to date to current alfred
---
src/mortimer/web_experiments/alfredo.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/mortimer/web_experiments/alfredo.py b/src/mortimer/web_experiments/alfredo.py
index a73a8f5..daa5dcc 100644
--- a/src/mortimer/web_experiments/alfredo.py
+++ b/src/mortimer/web_experiments/alfredo.py
@@ -236,7 +236,10 @@ def start(expid):
)
else:
abort(500)
-
+
+ page = request.args.get("page", None)
+ if page:
+ return redirect(url_for("alfredo.experiment", page=page))
return redirect(url_for("alfredo.experiment"))
@@ -254,7 +257,7 @@ def experiment():
if request.method == "GET":
url_pagename = request.args.get("page", None) # https://basepath.de/experiment?page=name
if url_pagename:
- experiment.movement_manager.jump_by_name(name=url_pagename)
+ experiment.movement_manager.move(direction=f"jump>{url_pagename}")
token = session["page_tokens"].get(tkey, uuid4().hex)
session["page_tokens"][tkey] = token
From e92df0596db30bb036dc31b0cda7f10efcacadb9 Mon Sep 17 00:00:00 2001
From: Johannes Brachem <37882800+jobrachem@users.noreply.github.com>
Date: Tue, 1 Mar 2022 18:28:09 +0100
Subject: [PATCH 03/13] update for compatibility to pymongo 4
---
src/mortimer/config.py | 2 +-
src/mortimer/models.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/mortimer/config.py b/src/mortimer/config.py
index cf2af96..7c58459 100644
--- a/src/mortimer/config.py
+++ b/src/mortimer/config.py
@@ -84,7 +84,7 @@ class BaseConfig:
MONGODB_SETTINGS["password"] = None
MONGODB_SETTINGS["authentication_source"] = "admin"
MONGODB_SETTINGS["ssl"] = False
- MONGODB_SETTINGS["ssl_ca_certs"] = None
+ MONGODB_SETTINGS["tlsCAFile"] = None
# Alfred settings
ALFRED_DB = "alfred"
diff --git a/src/mortimer/models.py b/src/mortimer/models.py
index 6667ba9..e8b4f85 100644
--- a/src/mortimer/models.py
+++ b/src/mortimer/models.py
@@ -163,7 +163,7 @@ def mongo_saving_agent(self) -> dict:
"user": self.alfred_user,
"password": f.decrypt(self.alfred_pw).decode(),
"use_ssl": str(appdb_config.get("ssl")).lower(),
- "ca_file_path": str(appdb_config.get("ssl_ca_certs")),
+ "ca_file_path": str(appdb_config.get("tlsCAFile")),
"activation_level": "1",
}
return {"mongo_saving_agent": mongo_config}
From 45d43a3a18349482711232fb342d5735f4a20031 Mon Sep 17 00:00:00 2001
From: Johannes Brachem <37882800+jobrachem@users.noreply.github.com>
Date: Tue, 1 Mar 2022 18:28:22 +0100
Subject: [PATCH 04/13] Update .gitignore
---
.gitignore | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitignore b/.gitignore
index 0ff6387..4246d08 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,3 +45,4 @@ dist/
mortimer_venv/
.mortimer/
.venv/
+.python-version
From 1bdfb557c56c112145735ecbb011bbf3ee8c81e1 Mon Sep 17 00:00:00 2001
From: Johannes Brachem <37882800+jobrachem@users.noreply.github.com>
Date: Mon, 21 Mar 2022 15:15:10 +0100
Subject: [PATCH 05/13] update metadata
---
CHANGELOG.md | 11 +++++++++++
src/mortimer/_version.py | 2 +-
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index db890ea..0d4c60a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## Mortimer v0.8.13 [unreleased]
+
+### Changed
+
+- (New) users are now allowed to remove documents in their own alfred3
+ mongoDB collections.
+
+### Fixed
+
+- Fixed support for url-jumping support
+
## Mortimer v0.8.12 (Released 2021-10-28)
### Added
diff --git a/src/mortimer/_version.py b/src/mortimer/_version.py
index 0c5e4de..df7f812 100644
--- a/src/mortimer/_version.py
+++ b/src/mortimer/_version.py
@@ -5,4 +5,4 @@
-__version__ = "0.8.12"
+__version__ = "0.8.13a"
From 1727c53cc43a147778b5f0b4237433fe269ff48c Mon Sep 17 00:00:00 2001
From: Johannes Brachem <37882800+jobrachem@users.noreply.github.com>
Date: Wed, 27 Apr 2022 19:42:21 +0200
Subject: [PATCH 06/13] add logging, close #78
---
src/mortimer/__init__.py | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/mortimer/__init__.py b/src/mortimer/__init__.py
index 76c4f68..02f8169 100644
--- a/src/mortimer/__init__.py
+++ b/src/mortimer/__init__.py
@@ -27,7 +27,15 @@
db = MongoEngine() # mortimer database
# application factory
-def create_app(instance_path=None):
+def create_app(instance_path=None, logfile: str = None):
+ logger = logging.getLogger("mortimer")
+ fh = logging.FileHandler(logfile)
+ formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
+ fh.setFormatter(formatter)
+
+ logger.addHandler(fh)
+ logger.setLevel(logging.INFO)
+
app = Flask(__name__, instance_path=instance_path)
# apply configuration
From 07243d6eee615513072a8efd3762eb849d8abb76 Mon Sep 17 00:00:00 2001
From: Johannes Brachem <37882800+jobrachem@users.noreply.github.com>
Date: Wed, 27 Apr 2022 19:42:45 +0200
Subject: [PATCH 07/13] remove log call
this log call is most likely overly verbose
---
src/mortimer/models.py | 8 --------
1 file changed, 8 deletions(-)
diff --git a/src/mortimer/models.py b/src/mortimer/models.py
index e8b4f85..a011fd8 100644
--- a/src/mortimer/models.py
+++ b/src/mortimer/models.py
@@ -273,14 +273,6 @@ def parse_exp_secrets(self) -> ExperimentSecrets:
try:
secrets_string = f.decrypt(self.exp_secrets).decode()
except TypeError:
- logger = logging.getLogger(__name__)
- logger.info(
- (
- "Exception during secrets decryption. "
- "To proceed, the value of secrets.conf was set to an empty string."
- f" Exp id={str(self.id)}"
- )
- )
secrets_string = ""
exp_secrets = ExperimentSecrets(expdir=self.path)
From ea799b57b079e38d7ddc7a25d03353a49bcf0072 Mon Sep 17 00:00:00 2001
From: Johannes Brachem <37882800+jobrachem@users.noreply.github.com>
Date: Wed, 27 Apr 2022 19:57:57 +0200
Subject: [PATCH 08/13] log 412 responses, close #79
---
src/mortimer/web_experiments/alfredo.py | 99 +++++++++++++++----------
1 file changed, 61 insertions(+), 38 deletions(-)
diff --git a/src/mortimer/web_experiments/alfredo.py b/src/mortimer/web_experiments/alfredo.py
index daa5dcc..1cfdc03 100644
--- a/src/mortimer/web_experiments/alfredo.py
+++ b/src/mortimer/web_experiments/alfredo.py
@@ -26,12 +26,16 @@
send_from_directory,
session,
url_for,
- jsonify
+ jsonify,
)
from flask_login import current_user
from mortimer.models import WebExperiment, User
-from mortimer.utils import create_fernet, is_social_media_preview, render_social_media_preview
+from mortimer.utils import (
+ create_fernet,
+ is_social_media_preview,
+ render_social_media_preview,
+)
from alfred3 import alfredlog
import alfred3.config
@@ -45,7 +49,7 @@ def __init__(self):
self.config = None
def generate_experiment(self, config=None): # pylint: disable=method-hidden
- """Hook for the ``generate_experiment`` function extracted from
+ """Hook for the ``generate_experiment`` function extracted from
the user's script.py. It is meant to be replaced in ``run.py``.
"""
@@ -75,7 +79,9 @@ def number_of_func_params(func):
def import_script(experiment_id):
- experiment = WebExperiment.objects.get_or_404(id=experiment_id) # pylint: disable=no-member
+ experiment = WebExperiment.objects.get_or_404(
+ id=experiment_id
+ ) # pylint: disable=no-member
# Fast path: see if the module has already been imported.
try:
@@ -127,11 +133,11 @@ def get(self, key):
self.lock.release()
if rv is None:
- try:
- print("Tried to access experiment with key %s" % key)
- print("Available Keys: %s" % list(self.experiments.keys()))
- except Exception:
- pass
+ molog = logging.getLogger("mortimer")
+ molog.warning(
+ f"Tried to access experiment with key '{key}'. Available Keys:"
+ f" {list(self.experiments.keys())}"
+ )
abort(412)
self.save(key, rv)
return rv
@@ -139,10 +145,11 @@ def get(self, key):
def remove_outdated(self):
self.lock.acquire()
current_time = int(time())
+ molog = logging.getLogger("mortimer")
for k in list(self.experiments.keys()):
v = self.experiments[k]
if current_time - v[0] > self.timeout:
- print("delete exp with key %s and last access time %s" % (k, v[0]))
+ molog.warning(f"Delete exp with key {k} and last access time {v[0]}")
del self.experiments[k]
self.lock.release()
@@ -170,17 +177,21 @@ def start(expid):
if is_social_media_preview(request.headers.get("User-Agent")):
return render_social_media_preview(config)
- if not experiment.public and experiment.password != request.form.get("password", None):
+ if not experiment.public and experiment.password != request.form.get(
+ "password", None
+ ):
exp_url = url_for("alfredo.start", expid=str(experiment.id))
return (
- '
Please enter the password
'
- % exp_url
+ 'Please enter the password
' % exp_url
)
-
+
args = request.args.to_dict()
test_mode = args.get("test") in ["true", "True", "TRUE"]
- debug_mode = args.get("debug") in ["true", "True", "TRUE"] or config.getboolean("general", "debug")
+ debug_mode = args.get("debug") in ["true", "True", "TRUE"] or config.getboolean(
+ "general", "debug"
+ )
if not experiment.active and not test_mode and not debug_mode:
return render_template("exp_inactive.html")
@@ -199,11 +210,8 @@ def start(expid):
try:
user_script = import_script(experiment.id)
exp_session = user_script.exp.create_session(
- session_id=sid,
- config=config,
- secrets=secrets,
- **request.args
- )
+ session_id=sid, config=config, secrets=secrets, **request.args
+ )
except Exception:
msg = "Error during creation of experiment session."
@@ -215,10 +223,11 @@ def start(expid):
"web_experiments.experiment",
username=current_user.username,
exp_title=experiment.title,
- ))
+ )
+ )
else:
abort(500)
-
+
try:
exp_session._start()
experiment_manager.save(sid, exp_session)
@@ -236,7 +245,7 @@ def start(expid):
)
else:
abort(500)
-
+
page = request.args.get("page", None)
if page:
return redirect(url_for("alfredo.experiment", page=page))
@@ -245,9 +254,14 @@ def start(expid):
@alfredo.route("/experiment", methods=["GET", "POST"])
def experiment():
+ molog = logging.getLogger("mortimer")
try:
sid = session["sid"]
except KeyError:
+ molog.warning(
+ "Experiment route called, but there was no session id in the session"
+ " cookie."
+ )
abort(412)
experiment = experiment_manager.get(sid)
@@ -255,13 +269,15 @@ def experiment():
try:
if request.method == "GET":
- url_pagename = request.args.get("page", None) # https://basepath.de/experiment?page=name
+ url_pagename = request.args.get(
+ "page", None
+ ) # https://basepath.de/experiment?page=name
if url_pagename:
experiment.movement_manager.move(direction=f"jump>{url_pagename}")
token = session["page_tokens"].get(tkey, uuid4().hex)
session["page_tokens"][tkey] = token
- session.modified = True # because the dict is mutable
+ session.modified = True # because the dict is mutable
current_page_html = make_response(experiment.ui.render_html(token))
current_page_html.cache_control.no_cache = True
@@ -272,11 +288,10 @@ def experiment():
submitted_token = request.values.get("page_token", None)
token = session["page_tokens"].pop(tkey, None)
- session.modified = True # because the dict is mutable
+ session.modified = True # because the dict is mutable
if not token or not token == submitted_token:
return redirect(url_for("alfredo.experiment"))
-
data = request.values.to_dict()
data.pop("move", None)
data.pop("directjump", None)
@@ -290,9 +305,11 @@ def experiment():
else:
abort(400)
return redirect(url_for("alfredo.experiment"))
-
+
except Exception:
- log = alfredlog.QueuedLoggingInterface("alfred3", f"exp.{str(experiment.exp_id)}")
+ log = alfredlog.QueuedLoggingInterface(
+ "alfred3", f"exp.{str(experiment.exp_id)}"
+ )
log.session_id = sid
msg = "Exception during experiment execution."
log.exception(msg)
@@ -314,9 +331,13 @@ def staticfile(identifier):
try:
sid = session["sid"]
experiment = experiment_manager.get(sid)
- path, content_type = experiment.user_interface_controller.get_static_file(identifier)
+ path, content_type = experiment.user_interface_controller.get_static_file(
+ identifier
+ )
dirname, filename = os.path.split(path)
- resp = make_response(send_from_directory(dirname, filename, mimetype=content_type))
+ resp = make_response(
+ send_from_directory(dirname, filename, mimetype=content_type)
+ )
# resp.cache_control.no_cache = True
return resp
@@ -329,13 +350,16 @@ def dynamicfile(identifier):
try:
sid = session["sid"]
experiment = experiment_manager.get(sid)
- strIO, content_type = experiment.user_interface_controller.get_dynamic_file(identifier)
+ strIO, content_type = experiment.user_interface_controller.get_dynamic_file(
+ identifier
+ )
except KeyError:
abort(404)
resp = make_response(send_file(strIO, mimetype=content_type))
resp.cache_control.no_cache = True
return resp
+
@alfredo.route("/callable/", methods=["GET", "POST"])
def callable(identifier):
try:
@@ -344,14 +368,14 @@ def callable(identifier):
f = experiment.user_interface_controller.get_callable(identifier)
except KeyError:
abort(404)
-
+
if request.content_type == "application/json":
values = request.get_json()
else:
values = request.values.to_dict()
-
- values.pop("_", None) # remove argument with name "_"
-
+
+ values.pop("_", None) # remove argument with name "_"
+
rv = f(**values)
if rv is not None:
resp = jsonify(rv)
@@ -359,4 +383,3 @@ def callable(identifier):
return resp
else:
return (" ", 204)
-
From 79ff8bfff927ed6c44f81349b3c9dace17c2e2fe Mon Sep 17 00:00:00 2001
From: Johannes Brachem <37882800+jobrachem@users.noreply.github.com>
Date: Wed, 27 Apr 2022 20:03:55 +0200
Subject: [PATCH 09/13] update meta
---
CHANGELOG.md | 5 +++++
src/mortimer/_version.py | 2 +-
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0d4c60a..27f5642 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed support for url-jumping support
+### Added
+
+- Added logging capability (#78)
+- Added log calls for 412 server responses (#79)
+
## Mortimer v0.8.12 (Released 2021-10-28)
### Added
diff --git a/src/mortimer/_version.py b/src/mortimer/_version.py
index df7f812..ad19d6f 100644
--- a/src/mortimer/_version.py
+++ b/src/mortimer/_version.py
@@ -5,4 +5,4 @@
-__version__ = "0.8.13a"
+__version__ = "0.8.13b"
From e0b164924c3a5c0e3911f868c1447fc410f3e0e6 Mon Sep 17 00:00:00 2001
From: Johannes Brachem <37882800+jobrachem@users.noreply.github.com>
Date: Wed, 27 Apr 2022 20:22:36 +0200
Subject: [PATCH 10/13] improve log messages (#79)
---
src/mortimer/web_experiments/alfredo.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/mortimer/web_experiments/alfredo.py b/src/mortimer/web_experiments/alfredo.py
index 1cfdc03..688bd86 100644
--- a/src/mortimer/web_experiments/alfredo.py
+++ b/src/mortimer/web_experiments/alfredo.py
@@ -135,7 +135,7 @@ def get(self, key):
if rv is None:
molog = logging.getLogger("mortimer")
molog.warning(
- f"Tried to access experiment with key '{key}'. Available Keys:"
+ f"Tried to access experiment with session id '{key}'. Available Keys:"
f" {list(self.experiments.keys())}"
)
abort(412)
@@ -149,7 +149,7 @@ def remove_outdated(self):
for k in list(self.experiments.keys()):
v = self.experiments[k]
if current_time - v[0] > self.timeout:
- molog.warning(f"Delete exp with key {k} and last access time {v[0]}")
+ molog.warning(f"Delete exp with session id '{k}' and last access time {v[0]}")
del self.experiments[k]
self.lock.release()
From 0e5cab89694506e4b994fae912345d896daf808d Mon Sep 17 00:00:00 2001
From: Johannes Brachem <37882800+jobrachem@users.noreply.github.com>
Date: Sat, 21 May 2022 17:31:29 +0200
Subject: [PATCH 11/13] fixes #82
---
src/mortimer/templates/experiment.html | 8 ++++----
src/mortimer/web_experiments/routes.py | 9 ++++++---
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/src/mortimer/templates/experiment.html b/src/mortimer/templates/experiment.html
index d2d9852..9664674 100644
--- a/src/mortimer/templates/experiment.html
+++ b/src/mortimer/templates/experiment.html
@@ -146,15 +146,15 @@ {{ n["fin"] }} / {{ n["tot
- {% if activity["last"] != 'none' %}
- {{ activity["last"] }}
+ {% if activity["last_time"] != 'none' %}
+ {{ activity["last_time"] }}
{% else %}
- none -
{% endif %}
- {% if activity["last"] != 'none' %}
- {{ activity["last"] }}
+ {% if activity["last_date"] != 'none' %}
+ {{ activity["last_date"] }}
{% else %}
- none -
{% endif %}
diff --git a/src/mortimer/web_experiments/routes.py b/src/mortimer/web_experiments/routes.py
index f646a4b..349372c 100644
--- a/src/mortimer/web_experiments/routes.py
+++ b/src/mortimer/web_experiments/routes.py
@@ -192,13 +192,16 @@ def experiment(username, exp_title):
if times:
try:
activity["first"] = datetime.fromtimestamp(times[0]["first"]).strftime('%Y-%m-%d, %H:%M')
- activity["last"] = datetime.fromtimestamp(times[0]["last"]).strftime('%H:%M')
+ activity["last_time"] = datetime.fromtimestamp(times[0]["last"]).strftime('%H:%M')
+ activity["last_date"] = datetime.fromtimestamp(times[0]["last"]).strftime('%Y-%m-%d')
except TypeError:
activity["first"] = times[0]["first"]
- activity["last"] = times[0]["last"]
+ activity["last_time"] = times[0]["last"]
+ activity["last_date"] = "none"
else:
activity["first"] = "none"
- activity["last"] = "none"
+ activity["last_time"] = "none"
+ activity["last_date"] = "none"
# Form for script.py upload
form = NewScriptForm()
From 0ada1c5b14688c147db520aea7a3fd24571e3dff Mon Sep 17 00:00:00 2001
From: Johannes Brachem <37882800+jobrachem@users.noreply.github.com>
Date: Sat, 21 May 2022 17:32:58 +0200
Subject: [PATCH 12/13] Update _version.py
---
src/mortimer/_version.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/mortimer/_version.py b/src/mortimer/_version.py
index ad19d6f..5b8d99b 100644
--- a/src/mortimer/_version.py
+++ b/src/mortimer/_version.py
@@ -5,4 +5,4 @@
-__version__ = "0.8.13b"
+__version__ = "0.8.13"
From c5680c4ad1b982cd0aaa20bd284d0041c9ac7029 Mon Sep 17 00:00:00 2001
From: Johannes Brachem <37882800+jobrachem@users.noreply.github.com>
Date: Sat, 21 May 2022 17:33:43 +0200
Subject: [PATCH 13/13] Update CHANGELOG.md
---
CHANGELOG.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 27f5642..45e8b90 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-## Mortimer v0.8.13 [unreleased]
+## Mortimer v0.8.13 (Released 2022-05-21)
### Changed
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Fixed support for url-jumping support
+- Fixed #82
### Added