Merge pull request #251 from raboof/show-oauth-error
Show error alert when oauth fails
diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml
index 1062ebd..8ea7174 100644
--- a/.github/workflows/integration-tests.yml
+++ b/.github/workflows/integration-tests.yml
@@ -52,7 +52,8 @@
- name: Setup python
uses: actions/setup-python@v2
with:
- python-version: '3.9'
+ # 3.12 current as of 2024
+ python-version: '3.12'
architecture: x64
- name: Install dependencies
run: |
@@ -60,6 +61,7 @@
pip install -r tools/requirements.txt
pip install -r server/requirements.txt
pip install -r test/requirements.txt
+ pip list
- name: Basic test
run: |
curl -sq "http://localhost:9200/_cluster/health?level=indices&pretty"
diff --git a/.github/workflows/type-tests.yml b/.github/workflows/type-tests.yml
index 16cab27..41632bd 100644
--- a/.github/workflows/type-tests.yml
+++ b/.github/workflows/type-tests.yml
@@ -4,6 +4,7 @@
push:
paths-ignore:
- '**/integration-tests.yml'
+ - '**/unittest.yml'
- 'test/itest*'
workflow_dispatch:
@@ -15,7 +16,8 @@
strategy:
max-parallel: 1
matrix:
- python-version: ["3.10", 3.7, 3.9]
+ # 3.8 EOL 2024-10 approx
+ python-version: [3.8, "3.10", 3.12]
steps:
- uses: actions/checkout@master
with:
diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml
index 077a395..43e66cf 100644
--- a/.github/workflows/unittest.yml
+++ b/.github/workflows/unittest.yml
@@ -13,10 +13,10 @@
runs-on: ubuntu-latest
strategy:
- max-parallel: 4
+ max-parallel: 1
matrix:
-# python-version: [2.7, 3.5, 3.6, 3.7]
- python-version: [3.7, "3.10"]
+ # 3.8 EOL 2024-10 approx
+ python-version: [3.8, "3.10", 3.12]
steps:
- uses: actions/checkout@master
@@ -37,7 +37,10 @@
python -m pip install --upgrade pip
pip install -r tools/requirements.txt
pip install -r test/requirements.txt
- pip install html2text # optional dependency, but needed for tests
+ # Later versions of html2text cause html-based tests to fail, because of a changed conversion
+ # This only affects the appearance of the message body, so does not matter for compatibility
+ pip install html2text==2020.1.16 # optional dependency, but needed for tests
+ pip list
- name: Check versions
run: |
webui/js/source/build.sh
diff --git a/server/plugins/messages.py b/server/plugins/messages.py
index 584df4d..7443954 100644
--- a/server/plugins/messages.py
+++ b/server/plugins/messages.py
@@ -558,6 +558,7 @@
"""Turns a flat array of emails into a nested structure of threads"""
for cur_email in sorted(self.emails, key=lambda x: x["epoch"]):
author = cur_email.get("from")
+ assert(author)
if author not in self.authors:
self.authors[author] = [0, cur_email.get("gravatar", "")]
self.authors[author][0] += 1
diff --git a/server/requirements.txt b/server/requirements.txt
index a9ad6f3..7642068 100644
--- a/server/requirements.txt
+++ b/server/requirements.txt
@@ -1,5 +1,5 @@
# Items in this file must have a licence compatible with AL 2.0
-PyYAML~=5.4.1 # WTFPL
+PyYAML~=6.0.1 # MIT
types-PyYAML # AL2.0
multipart~=0.2.1 # MIT
elasticsearch-dsl>=7.0.0,<8.0.0 # AL2.0
diff --git a/server/server_version.py b/server/server_version.py
index ad04347..a78d1f6 100644
--- a/server/server_version.py
+++ b/server/server_version.py
@@ -1,2 +1,2 @@
# This file is generated by server/update_version.sh
-PONYMAIL_SERVER_VERSION = '218c4f5'
+PONYMAIL_SERVER_VERSION = '4d644b1'
diff --git a/test/esintercept/elasticsearch.py b/test/esintercept/elasticsearch.py
new file mode 100644
index 0000000..4e43a70
--- /dev/null
+++ b/test/esintercept/elasticsearch.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Very simple module to intercept calls to Elasticsearch methods
+# Writes call parameters to a file.
+#
+# Use it by defining PYTHONPATH to include its parent dir, e.g.
+# [OUT=/tmp/pmfoal_out.txt] PYTHONPATH=test/esintercept python3 tools/archiver.py <file.eml
+# Redefine OUT to change the output file name
+
+import os
+import json
+
+# Dummy to satisf code
+VERSION = (7, 0, 1)
+VERSION_STR = "7.0.1"
+
+import atexit
+
+def exit_handler():
+ print("Closing %s" % outfile)
+ OUT.close()
+
+atexit.register(exit_handler)
+
+outfile=os.getenv('OUT','/tmp/pmfoal_out.txt')
+print("Opening %s" % outfile)
+OUT = open(outfile, 'w', encoding='utf-8')
+
+
+def show(method, *args, **kwargs):
+ OUT.write("======= Method: %s =======\n" % method)
+ bits = {
+ 'args': args,
+ 'kwargs': kwargs,
+ }
+ json.dump(bits, OUT, indent=2, sort_keys=True)
+ OUT.write("\n")
+
+class helpers:
+ def bulk(self,*args,**kwargs):
+ show('bulk', *args, **kwargs)
+
+class Indices:
+ def exists(self, *args, **kwargs):
+ show('exists', *args, **kwargs)
+ return True # Dummy value
+
+class Elasticsearch:
+
+ indices = Indices()
+
+ def __init__(self, *args, **kwargs):
+ show('Elasticsearch', *args,**kwargs)
+
+ def index(self, *args, **kwargs):
+ show('index', *args, **kwargs)
+
+ def info(self, *args, **kwargs):
+ show('info', *args, **kwargs)
+ return {"version": {"number": VERSION_STR}} # sufficient for testing
+
+class ConnectionError:
+ pass
+
+class AsyncElasticsearch(Elasticsearch):
+ pass
diff --git a/tools/archiver.py b/tools/archiver.py
index 2feb887..9d364fd 100755
--- a/tools/archiver.py
+++ b/tools/archiver.py
@@ -158,6 +158,7 @@
# Allow for empty string
if fd is None:
return None, None
+ assert(isinstance(fd, bytes)) # decode=True generates bytes
if filename:
attachment = {
"content_type": part.get_content_type(),
@@ -202,6 +203,7 @@
self.bytes = part.get_payload(decode=True)
self.html_as_source = False
if self.bytes is not None:
+ assert(isinstance(self.bytes, bytes)) # decode=True generates bytes
valid_encodings = [x for x in self.charsets if x]
if valid_encodings:
for cs in valid_encodings:
@@ -428,7 +430,11 @@
):
first_html = Body(part)
except Exception as err:
- print(err)
+ entry = sys.exc_info()[-1]
+ if entry: # avoid mypy complaint
+ print('Error on line {}:'.format(entry.tb_lineno), type(err).__name__, err)
+ else: # Should not happen, but just in case
+ print('Failed to create Body(part):',type(err).__name__, err)
# this requires a GPL lib, user will have to install it themselves
if first_html and (
@@ -759,7 +765,7 @@
# If we have a dump dir and ES failed, push to dump dir instead as a JSON object
# We'll leave it to another process to pick up the slack.
except Exception as err:
- print(err)
+ print('Error on line {}:'.format(sys.exc_info()[-1].tb_lineno), type(err).__name__, err)
if dump:
print(
"Pushing to ES failed, but dumponfail specified, dumping JSON docs"
diff --git a/tools/requirements.txt b/tools/requirements.txt
index 7a70f22..9aedca9 100644
--- a/tools/requirements.txt
+++ b/tools/requirements.txt
@@ -1,5 +1,5 @@
# Items in this file must have a licence compatible with AL 2.0
-PyYAML~=5.4.1 # WTFPL
+PyYAML~=6.0.1 # MIT
# elasticsearch-dsl>=7.0.0,<8.0.0 # AL2.0 - not used by tools currently
# N.B. ES 7.14 introduces strict server version compatibility checks
elasticsearch[async]>=7.13.1,<7.14.0 # AL2.0
diff --git a/webui/admin.html b/webui/admin.html
index 6473d30..53a2b1c 100644
--- a/webui/admin.html
+++ b/webui/admin.html
@@ -25,7 +25,7 @@
<!-- Bootstrap -->
<link href="css/bootstrap.min.css" rel="stylesheet" media="all">
- <link href="css/scaffolding.css?revision=f3a4716" rel="stylesheet" media="all">
+ <link href="css/scaffolding.css?revision=f8dc8ff" rel="stylesheet" media="all">
<link href="css/modal.css" rel="stylesheet" media="all">
<link href="css/spinner.css" rel="stylesheet" media="all">
<link rel="alternate" href="/api/static.lua"/>
@@ -79,9 +79,9 @@
<script src="js/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
- <script src="js/config.js?revision=f3a4716"></script>
- <script src="js/wordcloud.js?revision=f3a4716"></script>
- <script src="js/ponymail.js?revision=f3a4716"></script>
+ <script src="js/config.js?revision=f8dc8ff"></script>
+ <script src="js/wordcloud.js?revision=f8dc8ff"></script>
+ <script src="js/ponymail.js?revision=f8dc8ff"></script>
<div id="splash" class="splash fade-in"> </div>
<div style="clear: both;"></div>
</body>
diff --git a/webui/index.html b/webui/index.html
index ddcf7a4..b803470 100644
--- a/webui/index.html
+++ b/webui/index.html
@@ -24,7 +24,7 @@
<!-- Bootstrap -->
<link href="css/bootstrap.min.css" rel="stylesheet" media="all">
- <link href="css/scaffolding.css?revision=f3a4716" rel="stylesheet" media="all">
+ <link href="css/scaffolding.css?revision=f8dc8ff" rel="stylesheet" media="all">
<link href="css/modal.css" rel="stylesheet" media="all">
<link href="css/spinner.css" rel="stylesheet" media="all">
<link rel="alternate" href="/api/static.lua"/>
@@ -63,8 +63,8 @@
<script src="js/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
- <script src="js/config.js?revision=f3a4716"></script>
- <script src="js/ponymail.js?revision=f3a4716"></script>
+ <script src="js/config.js?revision=f8dc8ff"></script>
+ <script src="js/ponymail.js?revision=f8dc8ff"></script>
<div id="splash" class="splash fade-in"> </div>
<div style="clear: both;"></div>
diff --git a/webui/js/oauth.js b/webui/js/oauth.js
index 63ca3da..e855b40 100644
--- a/webui/js/oauth.js
+++ b/webui/js/oauth.js
@@ -30,18 +30,21 @@
xmlHttp.open("GET", theUrl, true);
xmlHttp.send(null);
xmlHttp.onreadystatechange = function(state) {
- if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
- if (callback) {
- try {
- callback(JSON.parse(xmlHttp.responseText), xstate);
- } catch (e) {
- callback(JSON.parse(xmlHttp.responseText), xstate)
+ if (xmlHttp.readyState == 4) {
+ if (xmlHttp.status == 200) {
+ if (callback) {
+ try {
+ callback(JSON.parse(xmlHttp.responseText), xstate);
+ } catch (e) {
+ callback(JSON.parse(xmlHttp.responseText), xstate)
+ }
}
- }
- }
- if (xmlHttp.readyState == 4 && xmlHttp.status == 404) {
- alert("404'ed: " + theUrl)
+ } else if (xmlHttp.status == 404) {
+ alert("404'ed: " + theUrl)
+ } else if (xmlHttp.status >= 500) {
+ alert("Internal error fetching " + theUrl + ": " + xmlHttp.responseText)
+ }
}
}
}
diff --git a/webui/js/ponymail.js b/webui/js/ponymail.js
index 6b6a35e..6f990fc 100644
--- a/webui/js/ponymail.js
+++ b/webui/js/ponymail.js
@@ -16,7 +16,7 @@
*/
// THIS IS AN AUTOMATICALLY COMBINED FILE. PLEASE EDIT THE source/ FILES!
-const PONYMAIL_REVISION = 'f3a4716';
+const PONYMAIL_REVISION = 'f8dc8ff';
/******************************************
@@ -627,7 +627,7 @@
quote = m[0];
i = quote.length;
t = splicer.substr(0, i);
- quote = quote.replace(/(>*\s*\r?\n)+$/g, "");
+ quote = quote.replace(/\n>[>\s]*$/g, "\n");
qdiv = new HTML('div', {
"class": "email_quote_parent"
}, [
@@ -694,8 +694,18 @@
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.send(content.join("&")); // send email as a POST string
- document.getElementById('composer_modal').style.display = 'none';
- modal("Message dispatched!", "Your email has been sent. Depending on moderation rules, it may take a while before it shows up in the archives.", "help");
+ request.onreadystatechange = function(state) {
+ if (request.readyState == 4) {
+ document.getElementById('composer_modal').style.display = 'none';
+ let response = JSON.parse(request.responseText)
+ if (response.error) {
+ modal("Message dispatch failed!", response.error, "error");
+ } else {
+ modal("Message dispatched!", "Your email has been sent. Depending on moderation rules, it may take a while before it shows up in the archives.", "help");
+ }
+ }
+ }
+
}
function compose_email(replyto, list) {
diff --git a/webui/js/source/composer.js b/webui/js/source/composer.js
index 7aabb8f..08fe5be 100644
--- a/webui/js/source/composer.js
+++ b/webui/js/source/composer.js
@@ -17,8 +17,18 @@
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.send(content.join("&")); // send email as a POST string
- document.getElementById('composer_modal').style.display = 'none';
- modal("Message dispatched!", "Your email has been sent. Depending on moderation rules, it may take a while before it shows up in the archives.", "help");
+ request.onreadystatechange = function(state) {
+ if (request.readyState == 4) {
+ document.getElementById('composer_modal').style.display = 'none';
+ let response = JSON.parse(request.responseText)
+ if (response.error) {
+ modal("Message dispatch failed!", response.error, "error");
+ } else {
+ modal("Message dispatched!", "Your email has been sent. Depending on moderation rules, it may take a while before it shows up in the archives.", "help");
+ }
+ }
+ }
+
}
function compose_email(replyto, list) {
diff --git a/webui/list.html b/webui/list.html
index 4006aee..87aa518 100644
--- a/webui/list.html
+++ b/webui/list.html
@@ -24,7 +24,7 @@
<!-- Bootstrap -->
<link href="css/bootstrap.min.css" rel="stylesheet" media="all">
- <link href="css/scaffolding.css?revision=f3a4716" rel="stylesheet" media="all">
+ <link href="css/scaffolding.css?revision=f8dc8ff" rel="stylesheet" media="all">
<link href="css/modal.css" rel="stylesheet" media="all">
<link href="css/spinner.css" rel="stylesheet" media="all">
<link rel="alternate" href="/api/static.lua"/>
@@ -181,9 +181,9 @@
</script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
- <script src="js/config.js?revision=f3a4716"></script>
- <script src="js/wordcloud.js?revision=f3a4716"></script>
- <script src="js/ponymail.js?revision=f3a4716"></script>
+ <script src="js/config.js?revision=f8dc8ff"></script>
+ <script src="js/wordcloud.js?revision=f8dc8ff"></script>
+ <script src="js/ponymail.js?revision=f8dc8ff"></script>
<div id="splash" class="splash fade-in"> </div>
<div style="clear: both;"></div>
<script type="text/javascript">
diff --git a/webui/oauth.html b/webui/oauth.html
index f44c0f8..833682c 100644
--- a/webui/oauth.html
+++ b/webui/oauth.html
@@ -21,7 +21,7 @@
<!-- CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet" media="all">
- <link href="css/scaffolding.css?revision=f3a4716" rel="stylesheet" media="all">
+ <link href="css/scaffolding.css?revision=f8dc8ff" rel="stylesheet" media="all">
<link href="css/modal.css" rel="stylesheet" media="all">
<link href="css/spinner.css" rel="stylesheet" media="all">
@@ -54,8 +54,8 @@
<script src="js/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
- <script src="js/config.js?revision=f3a4716"></script>
- <script src="js/ponymail.js?revision=f3a4716"></script>
- <script src="js/oauth.js?revision=f3a4716"></script>
+ <script src="js/config.js?revision=f8dc8ff"></script>
+ <script src="js/ponymail.js?revision=f8dc8ff"></script>
+ <script src="js/oauth.js?revision=f8dc8ff"></script>
</body>
</html>
diff --git a/webui/thread.html b/webui/thread.html
index d229418..70577ae 100644
--- a/webui/thread.html
+++ b/webui/thread.html
@@ -25,7 +25,7 @@
<!-- Bootstrap -->
<link href="css/bootstrap.min.css" rel="stylesheet" media="all">
- <link href="css/scaffolding.css?revision=f3a4716" rel="stylesheet" media="all">
+ <link href="css/scaffolding.css?revision=f8dc8ff" rel="stylesheet" media="all">
<link href="css/modal.css" rel="stylesheet" media="all">
<link href="css/spinner.css" rel="stylesheet" media="all">
<link rel="alternate" href="/api/static.lua"/>
@@ -97,9 +97,9 @@
<script src="js/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="js/bootstrap.min.js"></script>
- <script src="js/config.js?revision=f3a4716"></script>
- <script src="js/wordcloud.js?revision=f3a4716"></script>
- <script src="js/ponymail.js?revision=f3a4716"></script>
+ <script src="js/config.js?revision=f8dc8ff"></script>
+ <script src="js/wordcloud.js?revision=f8dc8ff"></script>
+ <script src="js/ponymail.js?revision=f8dc8ff"></script>
<div id="splash" class="splash fade-in"> </div>
<div style="clear: both;"></div>
</body>