Skip to content

Feature/public event #287

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 41 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
5ef6469
basic restoration of code from a deleted branch. includes- adding is_…
noam-y Feb 11, 2021
885a843
added 2 functions- one to send an adaptable email, with email body co…
noam-y Feb 11, 2021
1f4b084
added front end button to allow users to join event, not connected to…
noam-y Feb 11, 2021
8e0d1ee
adding testing fixtures
noam-y Feb 11, 2021
5a8adeb
adding working user and event fixture, adding is_public param to even…
noam-y Feb 11, 2021
59532d6
subtle changes for debugging add_user_to_event failing tests.
noam-y Feb 11, 2021
235c4b2
added something that prevents adding null event_id to userevent objects.
noam-y Feb 12, 2021
d32ca25
fixed a small bug that made one of the tests fail
noam-y Feb 12, 2021
ef0f679
added func that send email to participants given event id- there are …
noam-y Feb 12, 2021
c6477a5
email not working- last commit before rebuild
noam-y Feb 12, 2021
b7cc686
merged changes
noam-y Feb 12, 2021
540f1bf
merged with current changes + added one func that sends emails to all…
noam-y Feb 14, 2021
49ac8e7
improved documentation
noam-y Feb 14, 2021
e111110
adds feature that makes sure only the event owner can send email to a…
noam-y Feb 14, 2021
573cd2b
Merge branch 'develop' of https://github.com/PythonFreeCourse/calenda…
noam-y Feb 15, 2021
847eb09
merged changes w pulled code
noam-y Feb 15, 2021
b9d6016
Merge branch 'develop' into feature/public_event
yammesicka Feb 18, 2021
e715f4c
merging conflicts
noam-y Feb 18, 2021
14fc7e2
merge with code
noam-y Feb 18, 2021
f515361
trying to add is_public feature to telegram create event bot
noam-y Feb 18, 2021
e4f2ee0
creating more changes to enable public feature on create event func o…
noam-y Feb 18, 2021
9ffa3ea
last chance to add telegram feature- will be deleted soon...
noam-y Feb 18, 2021
e8571f1
reverting changes made on telegram
noam-y Feb 18, 2021
05c90a1
merging changes from pulled code
noam-y Feb 19, 2021
71ee772
changed email sending function to depend on send function so its more…
noam-y Feb 19, 2021
9cf15b1
moving user and event fixtures to conftest.py so we can use them glob…
noam-y Feb 20, 2021
70be019
changing mailing list sender to return the number of emails sent inst…
noam-y Feb 20, 2021
1bc712c
making test to assert failure of sending mailing list with no logged …
noam-y Feb 20, 2021
f371ce1
merging conflicts
noam-y Feb 20, 2021
05310b7
splitting mailing list send to 2 tests- one where no user is logged (…
noam-y Feb 20, 2021
c02ffd0
small pep changes
noam-y Feb 20, 2021
8a58f78
Merge branch 'develop' of https://github.com/PythonFreeCourse/calenda…
noam-y Feb 21, 2021
b6ff758
deleting some visual comments according to yam's commends + hooks
noam-y Feb 21, 2021
093881b
trying to add precommit hooks
noam-y Feb 23, 2021
7b4ee13
merge conflicts
noam-y Feb 25, 2021
986b43b
Merge branch 'feature/public_event' of https://github.com/noam-y/cale…
noam-y Feb 25, 2021
cf5b771
finally merged conflicts
noam-y Feb 26, 2021
76db81a
added guards and small changes
noam-y Feb 26, 2021
9bbed18
Merge branch 'develop' of https://github.com/PythonFreeCourse/calenda…
noam-y Feb 26, 2021
94c4a32
first try of adding koby's user system to event mailing list send
noam-y Feb 26, 2021
b08636e
moving user fixtures from conftest to user_fixtures.
noam-y Feb 26, 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
2 changes: 2 additions & 0 deletions app/database/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ class User(Base):
privacy = Column(String, default="Private", nullable=False)
is_manager = Column(Boolean, default=False)
language_id = Column(Integer, ForeignKey("languages.id"))
availability = Column(Boolean, default=True, nullable=False)
target_weight = Column(Float, nullable=True)

owned_events = relationship(
Expand Down Expand Up @@ -97,6 +98,7 @@ class Event(Base):
color = Column(String, nullable=True)
all_day = Column(Boolean, default=False)
invitees = Column(String)
is_public = Column(Boolean, default=False)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Event doesn't have "friends" option?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the meaning of friends is different- public event is meant to allow any user in the platform to join the event, just like the public events on facebook. so it means the owner's friends don't matter in this feature :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please explain what is the meaning of public/private event? is it like busy/free?
Thanks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a pubic event is event anyone can join. it means you don't need to be invited directly from the owner, you can join the event by yourself by clicking a button on event page

privacy = Column(String, default=PrivacyKinds.Public.name, nullable=False)
emotion = Column(String, nullable=True)
availability = Column(Boolean, default=True, nullable=False)
Expand Down
150 changes: 107 additions & 43 deletions app/internal/email.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,26 @@
from pydantic.errors import EmailError
from sqlalchemy.orm.session import Session

from app.config import (CALENDAR_HOME_PAGE, CALENDAR_REGISTRATION_PAGE,
CALENDAR_SITE_NAME, email_conf, templates)
from app.database.models import Event, User
from app.config import (
CALENDAR_HOME_PAGE,
CALENDAR_REGISTRATION_PAGE,
CALENDAR_SITE_NAME,
email_conf,
templates,
)
from app.database.models import Event, User, UserEvent
from app.internal.utils import get_current_user
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use Kobi's user system instead


mail = FastMail(email_conf)


def send(
session: Session, event_used: int, user_to_send: int,
title: str, background_tasks: BackgroundTasks = BackgroundTasks
session: Session,
event_used: int,
user_to_send: int,
title: str,
content: 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.
Expand All @@ -32,10 +42,8 @@ def send(
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()
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
if not verify_email_pattern(user_to_send.email):
Expand All @@ -45,18 +53,61 @@ def send(
recipients = {"email": [user_to_send.email]}.get("email")
body = f"begins at:{event_used.start} : {event_used.content}"

background_tasks.add_task(send_internal,
subject=subject,
recipients=recipients,
body=body)
background_tasks.add_task(
send_internal,
subject=subject,
recipients=recipients,
body=body + content,
)
return True


def send_email_invitation(sender_name: str,
recipient_name: str,
recipient_mail: str,
background_tasks: BackgroundTasks = BackgroundTasks
) -> bool:
def send_email_to_event_participants(
session: Session,
event_id: int,
title: str,
content: str,
) -> int:
"""This function sends emails to a mailing list of all event participants.
it uses the function send above to do this and avoid double codes..
Args:
session(Session): The session to redirect to the database.
event_id (int): Id number of the event that is used.
title (str): Title of the email that is being sent.
content (str): body of email sent.
Returns:
int: Returns the number of emails sent
(number of valid emails in event's participants)
"""
event_owner = session.query(Event.owner).filter(id == event_id).first()
if event_owner != get_current_user(session):
return 0
# makes sure only event owner can send an email via this func.
mailing_list = (
session.query(User.id, User.email)
.join(UserEvent, User.id == UserEvent.user_id)
.filter(event_id == event_id)
.all()
)
valid_mailing_list = list(filter(verify_email_pattern, mailing_list.email))
if not valid_mailing_list:
return 0
# making sure app doesn't crash if emails are invalid

event = session.query(Event).get(event_id)
subject = f"{event.title}: {title}"
for r in valid_mailing_list:
send(session, event, r.id, subject, content)
# sends the send email function parameters to send on the mailing list
return len(valid_mailing_list)


def send_email_invitation(
sender_name: str,
recipient_name: str,
recipient_mail: str,
background_tasks: BackgroundTasks = BackgroundTasks,
) -> bool:
"""
This function takes as parameters the sender's name,
the recipient's name and his email address, configuration, and
Expand All @@ -81,28 +132,35 @@ def send_email_invitation(sender_name: str,
return False

template = templates.get_template("invite_mail.html")
html = template.render(recipient=recipient_name, sender=sender_name,
site_name=CALENDAR_SITE_NAME,
registration_link=CALENDAR_REGISTRATION_PAGE,
home_link=CALENDAR_HOME_PAGE,
addr_to=recipient_mail)
html = template.render(
recipient=recipient_name,
sender=sender_name,
site_name=CALENDAR_SITE_NAME,
registration_link=CALENDAR_REGISTRATION_PAGE,
home_link=CALENDAR_HOME_PAGE,
addr_to=recipient_mail,
)

subject = "Invitation"
recipients = [recipient_mail]
body = html
subtype = "html"

background_tasks.add_task(send_internal,
subject=subject,
recipients=recipients,
body=body,
subtype=subtype)
background_tasks.add_task(
send_internal,
subject=subject,
recipients=recipients,
body=body,
subtype=subtype,
)
return True


def send_email_file(file_path: str,
recipient_mail: str,
background_tasks: BackgroundTasks = BackgroundTasks):
def send_email_file(
file_path: str,
recipient_mail: str,
background_tasks: BackgroundTasks = BackgroundTasks,
):
"""
his function takes as parameters the file's path,
the recipient's email address, configuration, and
Expand All @@ -126,19 +184,23 @@ def send_email_file(file_path: str,
body = "file"
file_attachments = [file_path]

background_tasks.add_task(send_internal,
subject=subject,
recipients=recipients,
body=body,
file_attachments=file_attachments)
background_tasks.add_task(
send_internal,
subject=subject,
recipients=recipients,
body=body,
file_attachments=file_attachments,
)
return True


async def send_internal(subject: str,
recipients: List[str],
body: str,
subtype: Optional[str] = None,
file_attachments: Optional[List[str]] = None):
async def send_internal(
subject: str,
recipients: List[str],
body: str,
subtype: Optional[str] = None,
file_attachments: Optional[List[str]] = None,
):
if file_attachments is None:
file_attachments = []

Expand All @@ -147,8 +209,10 @@ async def send_internal(subject: str,
recipients=[EmailStr(recipient) for recipient in recipients],
body=body,
subtype=subtype,
attachments=[UploadFile(file_attachment)
for file_attachment in file_attachments])
attachments=[
UploadFile(file_attachment) for file_attachment in file_attachments
],
)

return await send_internal_internal(message)

Expand Down
1 change: 1 addition & 0 deletions app/routers/email.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from app.internal.email import send as internal_send
from app.internal.email import send_email_invitation


router = APIRouter(
prefix="/email",
tags=["email"],
Expand Down
20 changes: 19 additions & 1 deletion app/routers/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from app.internal import comment as cmt
from app.internal.emotion import get_emotion
from app.internal.privacy import PrivacyKinds
from app.internal.utils import create_model, get_current_user
from app.internal.utils import create_model, save, get_current_user
from app.routers.categories import get_user_categories

EVENT_DATA = Tuple[Event, List[Dict[str, str]], str]
Expand Down Expand Up @@ -393,6 +393,7 @@ def create_event(
vc_link: str = None,
color: Optional[str] = None,
invitees: List[str] = None,
is_public: bool = False,
category_id: Optional[int] = None,
availability: bool = True,
is_google_event: bool = False,
Expand All @@ -416,6 +417,7 @@ def create_event(
color=color,
emotion=get_emotion(title, content),
invitees=invitees_concatenated,
is_public=is_public,
all_day=all_day,
category_id=category_id,
availability=availability,
Expand Down Expand Up @@ -516,6 +518,22 @@ def add_new_event(values: dict, db: Session) -> Optional[Event]:
return None


def add_user_to_event(session: Session, user_id: int, event_id: int):
user_already_connected = (
session.query(UserEvent)
.filter_by(event_id=event_id, user_id=user_id)
.all()
)
if not user_already_connected:
"""if user is not registered to the event, the system will add him"""
association = UserEvent(user_id=user_id, event_id=event_id)
save(session, association)
return True
# if the user has a connection to the event,
# the function will recognize the duplicate and return false.
return False


def get_template_to_share_event(
event_id: int,
user_name: str,
Expand Down
70 changes: 70 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import calendar
from datetime import datetime

import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

from app.config import PSQL_ENVIRONMENT
from app.database.models import Base
from app.routers.event import create_event
from app.routers.user import create_user

pytest_plugins = [
'tests.user_fixture',
Expand Down Expand Up @@ -80,3 +83,70 @@ def sqlite_engine():
@pytest.fixture
def Calendar():
return calendar.Calendar(0)


@pytest.fixture
def no_event_user(session):
"""a user made for testing who doesn't own any event."""
user = create_user(
session=session,
username='new_test_username',
password='new_test_password',
email='[email protected]',
language_id='english'
)

return user
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't create a new fixture, use one of the others.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i have to use several different users since i'm testing the use of the mailing list.



@pytest.fixture
def event_owning_user(session):
"""a user made for testing who already owns an event."""
user = create_user(
session=session,
username='new_test_username2',
password='new_test_password2',
email='[email protected]',
language_id='english'
)

data = {
'title': 'event_owning_user event',
'start': datetime.strptime('2021-05-05 14:59', '%Y-%m-%d %H:%M'),
'end': datetime.strptime('2021-05-05 15:01', '%Y-%m-%d %H:%M'),
'location': 'https://us02web.zoom.us/j/875384596',
'content': 'content',
'owner_id': user.id,
}

create_event(session, **data)

return user
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't create a new fixture, use one of the others. You can use a user fixture and an event fixture in your code to create this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i have to use several different users since i'm testing the use of the mailing list.

__



@pytest.fixture
def user1(session):
"""another user made for testing"""
user = create_user(
session=session,
username='user2user2',
password='verynicepass',
email='[email protected]',
language_id='english'
)
return user
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't create a new user fixture, use one of the others.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i have to use several different users since i'm testing mailing list.



@pytest.fixture
def event_example(session, event_owning_user):
data = {
'title': 'test event title',
'start': datetime.strptime('2021-05-05 14:59', '%Y-%m-%d %H:%M'),
'end': datetime.strptime('2021-05-05 15:01', '%Y-%m-%d %H:%M'),
'location': 'https://us02web.zoom.us/j/87538459r6',
'content': 'content',
'owner_id': event_owning_user.id,
}

event = create_event(session, **data)
return event
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't create a new event fixture, use one of the others.

Loading