Added email sending
All checks were successful
ci / build (push) Successful in 36s

This commit is contained in:
evdo 2025-04-01 15:20:23 +02:00
parent db2f98e63a
commit 16aa25a588
12 changed files with 211 additions and 12 deletions

View file

@ -1,20 +1,14 @@
# Используем официальный образ Python
FROM python:3.11-slim
# Устанавливаем рабочую директорию
WORKDIR /app
# Копируем зависимости
COPY requirements.txt .
# Устанавливаем зависимости
RUN pip install --no-cache-dir -r requirements.txt
# Копируем всё приложение в контейнер
COPY . .
# Указываем переменные окружения (они будут приходить извне)
ENV PYTHONUNBUFFERED=1
# Команда запуска сервера
CMD ["python", "weather_project/manage.py", "runserver", "0.0.0.0:8000"]

View file

@ -1,2 +1,4 @@
Django>=4.2
requests
celery
django-celery-beat

View file

@ -0,0 +1,5 @@
from django import forms
class EmailScheduleForm(forms.Form):
city = forms.CharField(max_length=100)
email = forms.EmailField()

View file

@ -0,0 +1,36 @@
import os
import requests
import logging
from celery import shared_task
from django.core.mail import send_mail
from django.conf import settings
logger = logging.getLogger(__name__)
API_KEY = 'a7cc162fc60a76d2e31461071634b8ce'
@shared_task
def send_weather_email(city, email):
url = f'https://api.openweathermap.org/data/2.5/weather?q={city}&appid={API_KEY}&units=metric&lang=en'
try:
response = requests.get(url)
response.raise_for_status()
data = response.json()
temp = data['main']['temp']
description = data['weather'][0]['description']
message = f"Weather in {city}: {description}, {temp}°C"
send_mail(
subject=f"Weather in {city}",
message=message,
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[email]
)
logger.info(f"[send_weather_email] Email sent successfully")
except Exception as e:
logger.exception(f"[send_weather_email] Failed: {e}")

View file

@ -34,7 +34,8 @@
width: 250px;
}
button {
button,
.link-button {
padding: 0.6rem 1.2rem;
font-size: 1rem;
border: none;
@ -43,9 +44,13 @@
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease;
text-decoration: none;
display: inline-block;
text-align: center;
}
button:hover {
button:hover,
.link-button:hover {
background-color: #0056b3;
}
@ -69,10 +74,15 @@
color: red;
font-weight: bold;
}
.bottom-link {
margin-top: 2rem;
}
</style>
</head>
<body>
<h1> EDP Weather Request</h1>
<h1>EDP Weather Request</h1>
<form method="post">
{% csrf_token %}
<input type="text" name="city" placeholder="Enter the name of the city" required>
@ -91,5 +101,9 @@
{% if error %}
<p class="error">{{ error }}</p>
{% endif %}
<div class="bottom-link">
<a href="{% url 'schedule_email' %}" class="link-button">Send Weather by Email</a>
</div>
</body>
</html>

View file

@ -0,0 +1,83 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Schedule Weather Email</title>
<style>
body {
font-family: "Segoe UI", sans-serif;
background: #f4f6f8;
margin: 0;
padding: 2rem;
display: flex;
flex-direction: column;
align-items: center;
}
h1 {
margin-bottom: 1rem;
font-size: 2.5rem;
color: #222;
}
form {
display: flex;
flex-direction: column;
gap: 1rem;
background-color: white;
padding: 2rem;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
max-width: 400px;
width: 100%;
}
input[type="text"],
input[type="email"],
input[type="time"] {
padding: 0.6rem 1rem;
font-size: 1rem;
border: 1px solid #ccc;
border-radius: 8px;
width: 100%;
}
button,
.link-button {
padding: 0.6rem 1.2rem;
font-size: 1rem;
border: none;
background-color: #007bff;
color: white;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease;
text-decoration: none;
text-align: center;
}
button:hover,
.link-button:hover {
background-color: #0056b3;
}
.bottom-link {
margin-top: 2rem;
}
</style>
</head>
<body>
<h1>Send Weather Email</h1>
<form method="post">
{% csrf_token %}
<input type="text" name="city" placeholder="Enter city" required>
<input type="email" name="email" placeholder="Enter your email" required>
<button type="submit">Send</button>
</form>
<div class="bottom-link">
<a href="{% url 'index' %}" class="link-button">Check Weather Online</a>
</div>
</body>
</html>

View file

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>Scheduled</title>
</head>
<body>
<h1>✅ Email scheduled successfully!</h1>
<a href="/">Go back</a>
</body>
</html>

View file

@ -1,6 +1,9 @@
from django.urls import path
from django.shortcuts import render
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('schedule/', views.schedule_email_view, name='schedule_email'),
path('success/', lambda request: render(request, 'weather/success.html'), name='email_scheduled_success')
]

View file

@ -2,7 +2,15 @@ import os
import time
import logging
import requests
from django.shortcuts import render
import json
import uuid
from django.shortcuts import render, redirect
from django_celery_beat.models import PeriodicTask, CrontabSchedule
from django.utils import timezone
from .forms import EmailScheduleForm
from .tasks import send_weather_email
logger = logging.getLogger(__name__)
@ -48,3 +56,21 @@ def index(request):
'weather': weather_data,
'error': error,
})
def schedule_email_view(request):
email_sent = False
if request.method == 'POST':
form = EmailScheduleForm(request.POST)
if form.is_valid():
city = form.cleaned_data['city']
email = form.cleaned_data['email']
send_weather_email.delay(city, email)
email_sent = True # флаг для шаблона
else:
form = EmailScheduleForm()
return render(request, 'weather/schedule_email.html', {'form': form, 'email_sent': email_sent})

View file

@ -0,0 +1,3 @@
from .celery import app as celery_app
__all__ = ['celery_app']

View file

@ -0,0 +1,8 @@
import os
from celery import Celery
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'weather_project.settings')
app = Celery('weather_project')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()

View file

@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/5.1/ref/settings/
"""
from pathlib import Path
from decouple import config
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
@ -37,6 +38,7 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_celery_beat',
'weather'
]
@ -154,3 +156,16 @@ LOGGING = {
},
},
}
# Celery broker
CELERY_BROKER_URL = 'amqp://guest:guest@localhost:5673//'
# Email
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'localhost'
EMAIL_PORT = 1025
EMAIL_USE_TLS = False
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
DEFAULT_FROM_EMAIL = 'test@example.com'