diff --git a/db/imapsync_results.db b/db/imapsync_results.db new file mode 100644 index 0000000..6ee2339 Binary files /dev/null and b/db/imapsync_results.db differ diff --git a/docker-compose.yml b/docker-compose.yml index 212861f..0124c7c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: - 143:143 - 993:993 volumes: - - vmail:/srv/mail + - ./vmail:/srv/mail - ./dovecot/config:/etc/dovecot - ./dovecot/passwd:/etc/dovecot/passwd @@ -17,7 +17,7 @@ services: networks: - default ports: - - 80:80 + - 8081:80 environment: - ROUNDCUBEMAIL_DEFAULT_HOST=dovecot - ROUNDCUBEMAIL_DEFAULT_PORT=143 @@ -45,7 +45,7 @@ services: container_name: streamlit restart: always ports: - - 81:80 + - 8082:80 volumes: - ./db:/app/db logging: @@ -60,6 +60,11 @@ services: volumes: vmail: + driver: local + driver_opts: + type: 'none' + o: 'bind' + device: './vmail' networks: default: diff --git a/dockerfile/imapsync-dockerfile b/dockerfile/imapsync-dockerfile index d174d47..97a857a 100644 --- a/dockerfile/imapsync-dockerfile +++ b/dockerfile/imapsync-dockerfile @@ -3,7 +3,7 @@ FROM debian:latest RUN apt update RUN apt upgrade -y RUN apt install -y git make gcc -RUN apt install -y apt-file cpanminus libc6-dev libssl-dev python3 python3-pip python3-dotenv libio-socket-inet6-perl +RUN apt install -y apt-file libio-socket-inet6-perl cpanminus libc6-dev libssl-dev python3 python3-pip python3-dotenv RUN apt install -y libperl-dev zlib1g-dev libnet-ssleay-perl RUN cpanm App::cpanminus Authen::NTLM CGI Compress::Zlib Crypt::OpenSSL::RSA Data::Dumper Data::Uniqid Dist::CheckConflicts Encode Encode::IMAPUTF7 File::Copy::Recursive File::Tail IO::Socket::INET IO::Socket::INET6 IO::Socket::SSL IO::Tee JSON JSON::WebToken LWP::UserAgent Mail::IMAPClient Module::ScanDeps PAR::Packer Pod::Usage Readonly Regexp::Common Sys::MemInfo Term::ReadKey Test::MockObject Test::More Test::Pod Unicode::String; exit 0 RUN apt install -y libproc-processtable-perl python3-requests iputils-ping @@ -18,5 +18,3 @@ WORKDIR /app/ COPY ../python_scripte/imapsync.py . COPY ../python_scripte/.env . ENTRYPOINT [ "python3","-u", "/app/imapsync.py" ] - -#RUN impasync-script \ No newline at end of file diff --git a/dockerfile/streamlit-dockerfile b/dockerfile/streamlit-dockerfile index 2019b79..487cf99 100644 --- a/dockerfile/streamlit-dockerfile +++ b/dockerfile/streamlit-dockerfile @@ -11,13 +11,13 @@ RUN apt-get update && apt-get install -y \ git \ && rm -rf /var/lib/apt/lists/* -RUN pip3 install -r /app/requirements.txt - EXPOSE 80 COPY ../python_scripte/streamlit-app.py /app/ COPY ../python_scripte/requirements.txt /app/ +RUN pip3 install -r /app/requirements.txt + HEALTHCHECK CMD curl --fail http://localhost:80/_stcore/health -ENTRYPOINT ["streamlit", "run", "/app/streamlit-app.py", "--server.port=80", "--server.address=0.0.0.0"] \ No newline at end of file +ENTRYPOINT ["streamlit", "run", "/app/streamlit-app.py", "--server.port=80", "--server.address=0.0.0.0"] diff --git a/python_scripte/.env b/python_scripte/.env index f557f4f..f7119a2 100644 --- a/python_scripte/.env +++ b/python_scripte/.env @@ -3,4 +3,4 @@ SMTP_PORT=587 SMTP_USER=serfling@itdata-gera.de SMTP_PASSWORD="xPElLoyD,94,#" FROM_EMAIL=serfling@itdata-gera.de -TO_EMAIL=serfling@itdata-gera.de +TO_EMAIL=b.goetze@trendsetzer.eu diff --git a/python_scripte/imapsync.py b/python_scripte/imapsync.py index f796f9d..52c910a 100644 --- a/python_scripte/imapsync.py +++ b/python_scripte/imapsync.py @@ -12,7 +12,7 @@ import time # Import time module for sleep functionality load_dotenv() # Define server details -host = "180.1.1.164" +host = "imap.strato.de" port = 993 # Function to send an email notification @@ -66,7 +66,8 @@ while True: id INTEGER PRIMARY KEY AUTOINCREMENT, email TEXT, messages_transferred INTEGER, - date TEXT + date TEXT, + auth_failed INTEGER DEFAULT 0 ) ''') @@ -92,13 +93,21 @@ while True: username, password, domain = user local_part = username.split('@')[0] print(f"User: {username} running.") + + # Check if the user previously had an authentication failure + cursor.execute("SELECT auth_failed FROM sync_results WHERE email = ? ORDER BY date DESC LIMIT 1", (username,)) + result = cursor.fetchone() + if result and result[0] == 1: + print(f"Skipping {username} due to previous authentication failure.") + # continue # Skip this user due to previous authentication failure + # Command for imapsync command = [ "imapsync", "--host1", domain, "--user1", username, "--password1", password, - "--host2", "180.1.1.164", + "--host2", "192.168.178.90", "--user2", "archiv@trendsetzer.eu", "--password2", "Ln0m2YQZd23H54L5tCiyjIBWLEn8mk36v7KauqS8QFGzu", "--subfolder2", f"{local_part}", @@ -112,29 +121,37 @@ while True: result = subprocess.run(command, capture_output=True, text=True) output = result.stdout + # Initialize variables + auth_failed = 0 + transferred_count = 0 + # Check for EXIT_AUTHENTICATION_FAILURE_USER error if "EXIT_AUTHENTICATION_FAILURE_USER" in output: subject = f"Authentication Failure for {username}" body = f"An authentication failure occurred for user {username} during IMAP sync." send_email(subject, body, os.getenv('TO_EMAIL')) + auth_failed = 1 # Mark authentication failure # Find and extract the "Messages transferred" line for line in output.splitlines(): if "Messages transferred" in line: transferred_messages = line.split(":")[-1].strip() transferred_count = int(transferred_messages) - current_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - - # Insert result into SQLite database - cursor.execute(''' - INSERT INTO sync_results (email, messages_transferred, date) - VALUES (?, ?, ?) - ''', (username, transferred_count, current_date)) - conn.commit() - print(f"Data inserted for {username}: {transferred_count} messages on {current_date}") break + + # Insert into the database if messages were transferred or if there was an auth failure + if transferred_count > 0 or auth_failed == 1: + current_date = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + # Insert result into SQLite database + cursor.execute(''' + INSERT INTO sync_results (email, messages_transferred, date, auth_failed) + VALUES (?, ?, ?, ?) + ''', (username, transferred_count, current_date, auth_failed)) + conn.commit() + print(f"Data inserted for {username}: {transferred_count} messages on {current_date}") else: - print(f"No 'Messages transferred' line found for {username}.") + print(f"No messages transferred for {username}.") except Exception as e: print(f"Error running imapsync for {username}: {e}") diff --git a/python_scripte/requirements.txt b/python_scripte/requirements.txt index ba7ae87..1e51534 100644 --- a/python_scripte/requirements.txt +++ b/python_scripte/requirements.txt @@ -1,3 +1,3 @@ -requests +streamlit pandas -streamlit \ No newline at end of file + diff --git a/python_scripte/streamlit-app.py b/python_scripte/streamlit-app.py index e1c37fe..1f41dba 100644 --- a/python_scripte/streamlit-app.py +++ b/python_scripte/streamlit-app.py @@ -1,10 +1,14 @@ import streamlit as st import sqlite3 import pandas as pd +from datetime import datetime, timedelta -def fetch_data_from_db(db_path, table_name): +def fetch_data_from_db(db_path, table_name, start_date=None, end_date=None): conn = sqlite3.connect(db_path) - query = f"SELECT * FROM {table_name}" + if table_name == "sync_results" and start_date and end_date: + query = f"SELECT * FROM {table_name} WHERE date BETWEEN '{start_date}' AND '{end_date}'" + else: + query = f"SELECT * FROM {table_name}" df = pd.read_sql_query(query, conn) conn.close() return df @@ -25,6 +29,9 @@ def delete_user_from_db(db_path, email): cursor.execute(''' DELETE FROM users WHERE email = ? ''', (email,)) + cursor.execute(''' + DELETE FROM sync_results WHERE email = ? + ''', (email,)) conn.commit() conn.close() @@ -82,6 +89,11 @@ def main(): emails.insert(0, "All") selected_email = st.selectbox("Filter by Email:", options=emails) + # Add date range picker for filtering results by date + st.subheader("Filter by Date Range:") + start_date = st.date_input("Start Date", value=datetime.now().date()) + end_date = st.date_input("End Date + 1 Tag", value=start_date + timedelta(days=1)) + if selected_email == "All": filtered_users_df = users_df else: @@ -91,16 +103,21 @@ def main(): # Display email transfer results if available if not results_df.empty: + # Filter by email and date if selected_email == "All": - st.write("Email Transfer Results:") - st.dataframe(results_df) + filtered_results_df = fetch_data_from_db(db_path, "sync_results", start_date=start_date, end_date=end_date) else: - filtered_results_df = results_df[results_df['email'] == selected_email] - if not filtered_results_df.empty: - st.write(f"Email Transfer Results for {selected_email}:") - st.dataframe(filtered_results_df) - else: - st.write(f"No transfer data found for {selected_email}.") + filtered_results_df = fetch_data_from_db(db_path, "sync_results", start_date=start_date, end_date=end_date) + filtered_results_df = filtered_results_df[filtered_results_df['email'] == selected_email] + + if not filtered_results_df.empty: + # Replace 'auth_failed' values with icons + filtered_results_df['auth_failed'] = filtered_results_df['auth_failed'].apply(lambda x: '✅' if x == 0 else '❌') + + st.write(f"Email Transfer Results for {selected_email}:") + st.dataframe(filtered_results_df) + else: + st.write(f"No transfer data found for {selected_email} in the selected date range.") else: st.write("No email transfer results available.")