Compare commits

...

3 Commits

Author SHA1 Message Date
2f13e87774 up website monitor 2025-10-01 17:51:12 +02:00
9a4a8155e2 caldav 2025-09-29 14:44:16 +02:00
96b3f76ea2 Add caldav 2025-09-29 14:27:40 +02:00
6 changed files with 142 additions and 20 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
portable_python

1
caldav/htpasswd Normal file
View File

@@ -0,0 +1 @@
username:password

26
caldav/readme.md Normal file
View File

@@ -0,0 +1,26 @@
how to make python portable
https://chat.mistral.ai/chat/ab946d87-22e6-47d4-a99c-e8522c077347
```
wget https://www.python.org/ftp/python/3.13.7/Python-3.13.7.tgz
tar -xzf Python-3.13.7.tgz
rm Python-3.13.7.tgz
cd Python-3.13.7
./configure --enable-optimizations --with-ensurepip=install --prefix=$(pwd)/portable_python
make -j$(nproc)
make install
# now in portable_python install packages that are needed
./portable_python/bin/pip3 install bcrypt
./portable_python/bin/pip3 install radicale
cd ..
mv Python-3.13.7/portable_python portable_python
rm -rf Python-3.13.7
cd ..
tar -czvf caldav.tar.gz caldav/
```
tar -xzf caldav.tar.gz

34
caldav/server.py Normal file
View File

@@ -0,0 +1,34 @@
from radicale import Application, config
from wsgiref.simple_server import make_server
import os
def run_server():
# Load default configuration
configuration = config.load()
# Customize settings
configuration.update({
"server": {
"hosts": "0.0.0.0:5232", # Listen on all interfaces
},
"storage": {
"filesystem_folder": "./calendars", # Store calendars here
},
"auth": {
"type": "htpasswd",
"htpasswd_filename": "./htpasswd", # Path to htpasswd file
"htpasswd_encryption": "autodetect", # or "sha1", "md5" (bcrypt is most secure)
},
})
# Create and run the app
app = Application(configuration=configuration)
server = make_server("0.0.0.0", 5232, app)
print("✅ Secure CalDAV server running on http://0.0.0.0:5232")
print("🔐 Authentication required. Default user: admin / password")
server.serve_forever()
if __name__ == "__main__":
run_server()

View File

@@ -0,0 +1,18 @@
{
"website": {
"url": "http://petrovv.com",
"check_interval_seconds": 600,
"timeout_seconds": 5
},
"email": {
"smtp_server": "mail.petrovv.com",
"smtp_port": 465,
"from_email": "monitor@petrovv.com",
"to_email": "nikola@petrovv.com",
"credentials_file": "credentials.txt"
},
"database": {
"path": "website_status.db",
"log_retention_days": 10
}
}

View File

@@ -4,6 +4,8 @@ import smtplib
from email.mime.text import MIMEText
import sqlite3
from datetime import datetime, timedelta
import json
import os
def read_credentials(file_path):
with open(file_path, 'r') as file:
@@ -19,13 +21,13 @@ def check_website(url, timeout=5):
except requests.RequestException:
return False
def send_email(subject, body, to_email, from_email, from_password, smtp_server):
def send_email(subject, body, to_email, from_email, from_password, smtp_server, smtp_port):
msg = MIMEText(body)
msg['Subject'] = subject
msg['From'] = from_email
msg['To'] = to_email
with smtplib.SMTP_SSL(smtp_server, 465) as server:
with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
server.login(from_email, from_password)
server.sendmail(from_email, to_email, msg.as_string())
@@ -36,20 +38,21 @@ def create_database(db_path):
CREATE TABLE IF NOT EXISTS website_status (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp DATETIME NOT NULL,
status INTEGER NOT NULL
current_status INTEGER NOT NULL,
previous_status INTEGER
)
''')
conn.commit()
conn.close()
def log_website_status(db_path, status):
def log_website_status(db_path, current_status, previous_status):
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
cursor.execute('''
INSERT INTO website_status (timestamp, status)
VALUES (?, ?)
''', (timestamp, 1 if status else 0))
INSERT INTO website_status (timestamp, current_status, previous_status)
VALUES (?, ?, ?)
''', (timestamp, 1 if current_status else 0, previous_status))
conn.commit()
conn.close()
@@ -57,7 +60,7 @@ def get_last_status(db_path):
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
cursor.execute('''
SELECT status FROM website_status
SELECT current_status FROM website_status
ORDER BY id DESC LIMIT 1
''')
result = cursor.fetchone()
@@ -71,50 +74,89 @@ def cleanup_old_logs(db_path, days_to_keep=10):
cutoff_date = (datetime.now() - timedelta(days=days_to_keep)).strftime('%Y-%m-%d %H:%M:%S')
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# Delete rows where current_status equals previous_status and timestamp is older than 10 days
cursor.execute('''
DELETE FROM website_status
WHERE timestamp < ?
WHERE timestamp < ? AND current_status = previous_status
''', (cutoff_date,))
deleted_rows = cursor.rowcount
conn.commit()
conn.close()
return deleted_rows
def print_config_example():
example_config = {
"website": {
"url": "http://petrovv.com",
"check_interval_seconds": 600,
"timeout_seconds": 5
},
"email": {
"smtp_server": "mail.petrovv.com",
"smtp_port": 465,
"from_email": "monitor@petrovv.com",
"to_email": "nikola@petrovv.com",
"credentials_file": "credentials.txt"
},
"database": {
"path": "website_status.db",
"log_retention_days": 10
}
}
print("Example config.json:")
print(json.dumps(example_config, indent=2))
def main():
url = "http://petrovv.com"
to_email = "nikola@petrovv.com"
check_interval = 600 # 10 minutes in seconds
credentials_file = "credentials.txt"
db_path = "website_status.db"
smtp_server = "mail.petrovv.com"
# Check if config.json exists
if not os.path.exists("config.json"):
print("Error: config.json not found.")
print_config_example()
return
# Load configuration
with open("config.json", "r") as f:
config = json.load(f)
url = config["website"]["url"]
to_email = config["email"]["to_email"]
check_interval = config["website"]["check_interval_seconds"]
credentials_file = config["email"]["credentials_file"]
db_path = config["database"]["path"]
smtp_server = config["email"]["smtp_server"]
smtp_port = config["email"]["smtp_port"]
log_retention_days = config["database"]["log_retention_days"]
create_database(db_path)
from_email, from_password = read_credentials(credentials_file)
last_status = None
last_status = get_last_status(db_path)
last_cleanup = datetime.now()
while True:
current_time = datetime.now()
current_status = check_website(url)
log_website_status(db_path, current_status)
log_website_status(db_path, current_status, last_status)
if last_status is None or current_status != (last_status == 1):
status_str = "up" if current_status else "down"
subject = f"Website Status Change: {status_str}"
body = f"The website {url} is now {status_str} at {current_time.strftime('%Y-%m-%d %H:%M:%S')}."
send_email(subject, body, to_email, from_email, from_password, smtp_server)
send_email(subject, body, to_email, from_email, from_password, smtp_server, smtp_port)
print_email_sent(status_str, current_time.strftime('%Y-%m-%d %H:%M:%S'))
last_status = 1 if current_status else 0
# Perform cleanup once per day
if (current_time - last_cleanup).days >= 1:
deleted = cleanup_old_logs(db_path, 10)
deleted = cleanup_old_logs(db_path, log_retention_days)
if deleted > 0:
print(f"[{current_time.strftime('%Y-%m-%d %H:%M:%S')}] Cleanup: Deleted {deleted} logs older than 10 days")
print(f"[{current_time.strftime('%Y-%m-%d %H:%M:%S')}] Cleanup: Deleted {deleted} logs older than {log_retention_days} days (keeping status changes)")
last_cleanup = current_time
time.sleep(check_interval)
if __name__ == "__main__":
main()