support multiple accounts, fix misc server issues
This commit is contained in:
parent
fb1180ae60
commit
953351e8a8
|
@ -32,7 +32,8 @@ Does not support different accounts.
|
||||||
```shell
|
```shell
|
||||||
SQLITE3_DB=<path to your sqlite3 database>
|
SQLITE3_DB=<path to your sqlite3 database>
|
||||||
HTTP_AUTH_PASS=<your encoded password>
|
HTTP_AUTH_PASS=<your encoded password>
|
||||||
```
|
EMAIL_ARCHIVE_ROOT=<archive root path>
|
||||||
|
```
|
||||||
5. `sudo chmod 600 /etc/secrets/imapviewer`
|
5. `sudo chmod 600 /etc/secrets/imapviewer`
|
||||||
6. Reload and start the service.
|
6. Reload and start the service.
|
||||||
|
|
||||||
|
|
54
server.py
54
server.py
|
@ -15,6 +15,8 @@ if not os.environ.get('SQLITE3_DB'):
|
||||||
raise Exception('SQLITE3_DB not set.')
|
raise Exception('SQLITE3_DB not set.')
|
||||||
if not os.environ.get('HTTP_AUTH_PASS'):
|
if not os.environ.get('HTTP_AUTH_PASS'):
|
||||||
raise Exception('HTTP_AUTH_PASS not set.')
|
raise Exception('HTTP_AUTH_PASS not set.')
|
||||||
|
if not os.environ.get('EMAIL_ARCHIVE_ROOT'):
|
||||||
|
raise Exception('EMAIL_ARCHIVE_ROOT not set.')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
user_password = base64.b64decode(os.environ.get('HTTP_AUTH_PASS')).decode().replace('\n', '')
|
user_password = base64.b64decode(os.environ.get('HTTP_AUTH_PASS')).decode().replace('\n', '')
|
||||||
|
@ -34,12 +36,6 @@ def get_pw(username):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_db_connection():
|
|
||||||
conn = sqlite3.connect(os.environ.get('SQLITE3_DB'))
|
|
||||||
conn.row_factory = sqlite3.Row
|
|
||||||
return conn
|
|
||||||
|
|
||||||
|
|
||||||
def dict_from_row(row):
|
def dict_from_row(row):
|
||||||
return dict(zip(row.keys(), row))
|
return dict(zip(row.keys(), row))
|
||||||
|
|
||||||
|
@ -47,45 +43,59 @@ def dict_from_row(row):
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
@auth.login_required
|
@auth.login_required
|
||||||
def index():
|
def index():
|
||||||
conn = get_db_connection()
|
return render_template('index.html', accounts=[x.name for x in list(Path(os.environ.get('EMAIL_ARCHIVE_ROOT')).iterdir())])
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/<email_account>/')
|
||||||
|
@auth.login_required
|
||||||
|
def account(email_account):
|
||||||
|
conn = get_db_connection(email_account)
|
||||||
folders = conn.execute('SELECT name, table_name FROM folders_mapping').fetchall()
|
folders = conn.execute('SELECT name, table_name FROM folders_mapping').fetchall()
|
||||||
syncs = conn.execute('SELECT * FROM syncs ORDER BY timestamp DESC').fetchall()
|
syncs = conn.execute('SELECT * FROM syncs ORDER BY timestamp DESC').fetchall()
|
||||||
conn.close()
|
conn.close()
|
||||||
syncs = [dict_from_row(sync) for sync in syncs]
|
syncs = [dict_from_row(sync) for sync in syncs]
|
||||||
for sync in syncs:
|
for sync in syncs:
|
||||||
sync['timestamp'] = datetime.fromtimestamp(sync['timestamp']).strftime('%Y-%m-%d %H:%M:%S')
|
sync['timestamp'] = datetime.fromtimestamp(sync['timestamp']).strftime('%Y-%m-%d %H:%M:%S')
|
||||||
return render_template('index.html', folders=folders, syncs=syncs)
|
return render_template('account.html', folders=folders, syncs=syncs, email_account=email_account)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/folder/<table_name>')
|
@app.route('/<email_account>/folder/<table_name>')
|
||||||
@auth.login_required
|
@auth.login_required
|
||||||
def folder(table_name):
|
def folder(email_account, table_name):
|
||||||
conn = get_db_connection()
|
conn = get_db_connection(email_account)
|
||||||
emails = conn.execute(f'SELECT * FROM {table_name} ORDER BY timestamp DESC').fetchall()
|
emails = conn.execute(f'SELECT * FROM {table_name} ORDER BY timestamp DESC').fetchall()
|
||||||
conn.close()
|
conn.close()
|
||||||
emails = [dict_from_row(email) for email in emails]
|
emails = [dict_from_row(email) for email in emails]
|
||||||
for email in emails:
|
for email in emails:
|
||||||
email['timestamp'] = datetime.fromtimestamp(email['timestamp']).strftime('%Y-%m-%d %H:%M:%S')
|
email['timestamp'] = datetime.fromtimestamp(email['timestamp']).strftime('%Y-%m-%d %H:%M:%S')
|
||||||
return render_template('folder.html', emails=emails, table_name=table_name)
|
return render_template('folder.html', emails=emails, table_name=table_name, email_account=email_account)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/email/<table_name>/<id>')
|
@app.route('/<email_account>/email/<table_name>/<id>')
|
||||||
@auth.login_required
|
@auth.login_required
|
||||||
def email(table_name, id):
|
def email(email_account, table_name, id):
|
||||||
conn = get_db_connection()
|
conn = get_db_connection(email_account)
|
||||||
email = conn.execute(f'SELECT * FROM {table_name} WHERE id = ?', (id,)).fetchone()
|
email = dict_from_row(conn.execute(f'SELECT * FROM {table_name} WHERE id = ?', (id,)).fetchone())
|
||||||
conn.close()
|
conn.close()
|
||||||
email = dict_from_row(email)
|
|
||||||
email['timestamp'] = datetime.fromtimestamp(email['timestamp']).strftime('%Y-%m-%d %H:%M:%S')
|
email['timestamp'] = datetime.fromtimestamp(email['timestamp']).strftime('%Y-%m-%d %H:%M:%S')
|
||||||
attachments = json.loads(email['attachments'])
|
attachments = json.loads(email['attachments'])
|
||||||
return render_template('email.html', email=email, attachments=attachments)
|
return render_template('email.html', email=email, attachments=attachments, email_account=email_account)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/attachments/<path:filename>')
|
@app.route('/<email_account>/attachments/<path:filename>')
|
||||||
@auth.login_required
|
@auth.login_required
|
||||||
def download_file(filename):
|
def download_file(email_account, filename):
|
||||||
mimetype = magic.from_file(str(Path('attachments', filename)), mime=True)
|
p = Path(os.environ.get('EMAIL_ARCHIVE_ROOT'), email_account, 'attachments', filename)
|
||||||
return send_from_directory('attachments', filename, mimetype=mimetype)
|
if not p.exists():
|
||||||
|
return 404
|
||||||
|
mimetype = magic.from_file(str(p), mime=True)
|
||||||
|
return send_from_directory(Path(os.environ.get('EMAIL_ARCHIVE_ROOT'), email_account, 'attachments'), filename, mimetype=mimetype)
|
||||||
|
|
||||||
|
|
||||||
|
def get_db_connection(email_account):
|
||||||
|
conn = sqlite3.connect(os.path.join(os.environ.get('EMAIL_ARCHIVE_ROOT'), email_account, 'emails.db'))
|
||||||
|
conn.row_factory = sqlite3.Row
|
||||||
|
return conn
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Email Folders</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Email Folders</h1>
|
||||||
|
<h3>{{ email_account }}</h3>
|
||||||
|
<ul>
|
||||||
|
{% for folder in folders %}
|
||||||
|
<li><a href="{{ url_for('folder', email_account=email_account, table_name=folder.table_name) }}">{{ folder.name }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
<h1>Last Syncs</h1>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>New Emails</th>
|
||||||
|
<th>New Attachments</th>
|
||||||
|
<th>Duration</th>
|
||||||
|
</tr>
|
||||||
|
{% for sync in syncs %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ sync.timestamp }}</td>
|
||||||
|
<td>{{ sync.type }}</td>
|
||||||
|
<td>{{ sync.new_emails }}</td>
|
||||||
|
<td>{{ sync.new_attachments }}</td>
|
||||||
|
<td>{{ sync.duration }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
<style>
|
||||||
|
ul {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</html>
|
|
@ -8,7 +8,7 @@
|
||||||
<h2>Attachments</h2>
|
<h2>Attachments</h2>
|
||||||
<ul>
|
<ul>
|
||||||
{% for attachment in attachments %}
|
{% for attachment in attachments %}
|
||||||
<a href="{{ url_for('download_file', filename='F' + attachment.hash) }}">{{ attachment.filename }}</a>
|
<a href="{{ url_for('download_file', email_account=email_account, filename='F' + attachment.hash) }}">{{ attachment.filename }}</a>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
<h2>Content</h2>
|
<h2>Content</h2>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
<ul>
|
<ul>
|
||||||
{% for email in emails %}
|
{% for email in emails %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ url_for('email', table_name=table_name, id=email.id) }}">
|
<a href="{{ url_for('email', email_account=email_account, table_name=table_name, id=email.id) }}">
|
||||||
{{ email.timestamp }} | <i>{{ email.from_email }}</i> - <strong>{{ email.subject }}</strong>
|
{{ email.timestamp }} | <i>{{ email.from_email }}</i> - <strong>{{ email.subject }}</strong>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -1,39 +1,14 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Email Folders</title>
|
<title>Email Archive</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Email Folders</h1>
|
<h3>Accounts</h3>
|
||||||
<ul>
|
<ul>
|
||||||
{% for folder in folders %}
|
{% for account in accounts %}
|
||||||
<li><a href="{{ url_for('folder', table_name=folder.table_name) }}">{{ folder.name }}</a></li>
|
<li><a href="/{{ account }}">{{ account }}</a></li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
<h1>Last Syncs</h1>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>Timestamp</th>
|
|
||||||
<th>Type</th>
|
|
||||||
<th>New Emails</th>
|
|
||||||
<th>New Attachments</th>
|
|
||||||
<th>New Folders</th>
|
|
||||||
<th>Duration</th>
|
|
||||||
</tr>
|
|
||||||
{% for sync in syncs %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ sync.timestamp }}</td>
|
|
||||||
<td>{{ sync.type }}</td>
|
|
||||||
<td>{{ sync.new_emails }}</td>
|
|
||||||
<td>{{ sync.new_attachments }}</td>
|
|
||||||
<td>{{ sync.duration }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
</body>
|
</body>
|
||||||
<style>
|
|
||||||
ul {
|
|
||||||
list-style-type: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Reference in New Issue