Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
d6ee4f8
Feat/Basic Email use
PureDreamer Jan 16, 2021
2d3fab5
Feat/basic_email_send
PureDreamer Jan 16, 2021
996d190
revert env setting
PureDreamer Jan 16, 2021
68c9209
Changed tests
PureDreamer Jan 16, 2021
9571245
changed file directories
PureDreamer Jan 18, 2021
100438b
added demo templates
PureDreamer Jan 19, 2021
0c76176
Merge remote-tracking branch 'upstream/develop' into feature/email_send
PureDreamer Jan 19, 2021
7d01ce9
Changed to match with current commit
PureDreamer Jan 19, 2021
85a57c8
Update config.py
PureDreamer Jan 19, 2021
4bdb4bb
Update config.py.example
PureDreamer Jan 19, 2021
404561b
Update config.py
PureDreamer Jan 19, 2021
ec8b3ab
fixed config
PureDreamer Jan 19, 2021
335a954
Update requirements.txt
PureDreamer Jan 19, 2021
2950fcc
typing email_conf
PureDreamer Jan 19, 2021
a086ab3
Pass validation pydantic
PureDreamer Jan 19, 2021
82ab42c
Update config.py.example
PureDreamer Jan 19, 2021
09b0ebe
Update test_email.py
PureDreamer Jan 19, 2021
f843285
Update test_email.py
PureDreamer Jan 19, 2021
8a4b5b8
Another Try with fastapi mail
PureDreamer Jan 19, 2021
5292cd1
smtpd mock
PureDreamer Jan 19, 2021
11e87e0
Update test_email.py
PureDreamer Jan 19, 2021
a0ff240
Update test_email.py
PureDreamer Jan 19, 2021
4a9366c
try to override error connection
PureDreamer Jan 19, 2021
14168bb
Update test_email.py
PureDreamer Jan 19, 2021
b9f6bf0
Update test_email.py
PureDreamer Jan 19, 2021
979e67d
Update test_email.py
PureDreamer Jan 19, 2021
ece2d73
update
PureDreamer Jan 19, 2021
0979a94
Update test_email.py
PureDreamer Jan 19, 2021
eccb52a
Update test_email.py
PureDreamer Jan 19, 2021
9c5d3ca
conf add plugin
PureDreamer Jan 19, 2021
bd760be
Update test_email.py
PureDreamer Jan 19, 2021
ff84deb
Update test_email.py
PureDreamer Jan 19, 2021
de1c620
Changed requested changes
PureDreamer Jan 20, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added app/config.py
Empty file.
14 changes: 14 additions & 0 deletions app/config.py.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import os

from fastapi_mail import ConnectionConfig
# flake8: noqa


Expand All @@ -8,3 +11,14 @@ DEVELOPMENT_DATABASE_STRING = "sqlite:///./dev.db"
MEDIA_DIRECTORY = 'media'
PICTURE_EXTENSION = '.png'
AVATAR_SIZE = (120, 120)

email_conf = ConnectionConfig(
MAIL_USERNAME=os.getenv("MAIL_USERNAME") or "user",
MAIL_PASSWORD=os.getenv("MAIL_PASSWORD") or "password",
MAIL_FROM=os.getenv("MAIL_FROM") or "a@a.com",
MAIL_PORT=587,
MAIL_SERVER="smtp.gmail.com",
MAIL_TLS=True,
MAIL_SSL=False,
USE_CREDENTIALS=True,
)
40 changes: 40 additions & 0 deletions app/internal/email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from app.config import email_conf
from app.database.models import Event, User
from fastapi import BackgroundTasks
from fastapi_mail import FastMail, MessageSchema
from sqlalchemy.orm.session import Session

mail = FastMail(email_conf)


def send(
session: Session, event_used: int, user_to_send: int,
title: str, background_tasks: BackgroundTasks = BackgroundTasks
) -> bool:
"""This function is being used to send emails in the background.
It takes an event and a user and it sends the event to the user.

Args:
session(Session): The session to redirect to the database.
title (str): Title of the email that is being sent.
event_used (int): Id number of the event that is used.
user_to_send (int): Id number of user that we want to notify.
background_tasks (BackgroundTasks): Function from fastapi that lets
you apply tasks in the background.

Returns:
bool: Returns True if the email was sent, else returns False.
"""
event_used = session.query(Event).filter(
Event.id == event_used).first()
user_to_send = session.query(User).filter(
User.id == user_to_send).first()
if not user_to_send or not event_used:
return False
message = MessageSchema(
subject=f"{title} {event_used.title}",
recipients={"email": [user_to_send.email]}.get("email"),
body=f"begins at:{event_used.start} : {event_used.content}",
)
background_tasks.add_task(mail.send_message, message)
return True
4 changes: 3 additions & 1 deletion app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from app.database.database import engine
from app.dependencies import (
MEDIA_PATH, STATIC_PATH, templates)
from app.routers import agenda, event, profile
from app.routers import agenda, event, profile, email


models.Base.metadata.create_all(bind=engine)
Expand All @@ -17,11 +17,13 @@
app.include_router(profile.router)
app.include_router(event.router)
app.include_router(agenda.router)
app.include_router(email.router)


@app.get("/")
async def home(request: Request):
return templates.TemplateResponse("home.html", {
"request": request,
"message": "Hello, World!"

})
Binary file added app/media/fake_user.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions app/routers/email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from app.database.database import get_db
from app.internal.email import send as internal_send
from fastapi import APIRouter, BackgroundTasks, Depends, Form, HTTPException
from sqlalchemy.orm.session import Session
from starlette.responses import RedirectResponse

router = APIRouter(
prefix="/email",
tags=["email"],
responses={404: {"description": "Not found"}},
)


@router.post("/send")
async def send(
db: Session = Depends(get_db),
send_to: str = "/",
title: str = Form(...),
event_used: str = Form(...),
user_to_send: str = Form(...),
background_tasks: BackgroundTasks = BackgroundTasks
) -> RedirectResponse:
if not internal_send(
title=title, event_used=event_used,
user_to_send=user_to_send,
background_tasks=background_tasks, session=db):
raise HTTPException(status_code=404, detail="Couldn't send the email!")
return RedirectResponse(send_to, status_code=303)
28 changes: 28 additions & 0 deletions app/templates/demo/home_email.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{% extends "base.html" %}

{% block content %}

<div class="container mt-4">
<h1>{{message}}</h1>
</div>

<div>
<form action="/email/send" method="post">
<!-- Example of how to use sending email
This is a testing using ids of evenets and users yet with
simple manipulation you could send it how ever you want -->
<label for="event_used">Event Id</label><br>
<input type="text" value="{{ event_used }}" name="event_used"><br>
<label for="user_to_send">User Id</label><br>
<input type="text" value="{{user_to_send}}" name="user_to_send">
<div>
<select class="form-control" name="title">
<option value="New Event:">New Event</option>
<option value="Reminder:">Reminder</option>
<option value="Canceled:">Canceled</option>
<option value="Updated">Updated</option>
</select>
</div>
<input type="submit" value="Accept">
</form>
{% endblock %}
10 changes: 4 additions & 6 deletions app/templates/home.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
{% extends "base.html" %}


{% block content %}

<div class="container mt-4">
<h1>{{message}}</h1>
</div>

<div class="container mt-4">
<h1>{{message}}</h1>
</div>

{% endblock %}
{% endblock %}
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ click==7.1.2
colorama==0.4.4
coverage==5.3.1
fastapi==0.63.0
fastapi_mail==0.3.3.1
faker==5.6.2
smtpdfix==0.2.6
h11==0.12.0
h2==4.0.0
hpack==4.0.0
Expand Down
40 changes: 33 additions & 7 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from fastapi.testclient import TestClient
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
import datetime

from app.main import app
import pytest
from app.database.database import Base, SessionLocal, engine
from app.database.models import User
from app.database.models import Event, User
from app.main import app
from app.routers import profile

from faker import Faker
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
pytest_plugins = "smtpdfix"

SQLALCHEMY_TEST_DATABASE_URL = "sqlite:///./test.db"

Expand Down Expand Up @@ -36,6 +38,30 @@ def session():
Base.metadata.drop_all(bind=engine)


@pytest.fixture
def user(session):
faker = Faker()
user1 = User(username=faker.first_name(), email=faker.email())
session.add(user1)
session.commit()
yield user1
session.delete(user1)
session.commit()


@pytest.fixture
def event(session, user):
event1 = Event(
title="Test Email", content="Test TEXT",
start=datetime.datetime.now(),
end=datetime.datetime.now(), owner_id=user.id)
session.add(event1)
session.commit()
yield event1
session.delete(event1)
session.commit()


def get_test_placeholder_user():
return User(
username='fake_user',
Expand Down
34 changes: 34 additions & 0 deletions tests/test_email.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@


from app.internal.email import mail
from fastapi import BackgroundTasks


def test_email_send(client, user, event, smtpd):
mail.config.SUPPRESS_SEND = 1
mail.config.MAIL_SERVER = smtpd.hostname
mail.config.MAIL_PORT = smtpd.port
mail.config.USE_CREDENTIALS = False
mail.config.MAIL_TLS = False
with mail.record_messages() as outbox:
response = client.post(
"/email/send", data={
"event_used": event.id, "user_to_send": user.id,
"title": "Testing",
"background_tasks": BackgroundTasks})
assert len(outbox) == 1
assert response.ok


def test_failed_email_send(client, user, event, smtpd):
mail.config.SUPPRESS_SEND = 1
mail.config.MAIL_SERVER = smtpd.hostname
mail.config.MAIL_PORT = smtpd.port
with mail.record_messages() as outbox:
response = client.post(
"/email/send", data={
"event_used": event.id + 1, "user_to_send": user.id,
"title": "Testing",
"background_tasks": BackgroundTasks})
assert len(outbox) == 0
assert not response.ok