Skip to content
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

Feature/public event #287

Open
wants to merge 41 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 4 additions & 2 deletions app/database/models.py
Expand Up @@ -38,8 +38,8 @@ class UserFeature(Base):
__tablename__ = "user_feature"

id = Column(Integer, primary_key=True, index=True)
feature_id = Column('feature_id', Integer, ForeignKey('features.id'))
user_id = Column('user_id', Integer, ForeignKey('users.id'))
feature_id = Column("feature_id", Integer, ForeignKey("features.id"))
user_id = Column("user_id", Integer, ForeignKey("users.id"))

is_enable = Column(Boolean, default=False)

Expand All @@ -60,6 +60,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 @@ -124,6 +125,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)
image = Column(String, nullable=True)
Expand Down
49 changes: 46 additions & 3 deletions app/internal/email.py
@@ -1,7 +1,7 @@
import os
from typing import List, Optional

from fastapi import BackgroundTasks, UploadFile
from fastapi import BackgroundTasks, Depends, UploadFile
from fastapi_mail import FastMail, MessageSchema
from pydantic import EmailStr
from pydantic.errors import EmailError
Expand All @@ -14,8 +14,9 @@
DOMAIN,
email_conf,
)
from app.database.models import Event, User
from app.database.models import Event, User, UserEvent
from app.dependencies import templates
from app.internal.security.dependencies import current_user
from app.internal.security.schema import ForgotPassword

mail = FastMail(email_conf)
Expand All @@ -26,6 +27,7 @@ def send(
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.
Expand Down Expand Up @@ -57,11 +59,52 @@ def send(
send_internal,
subject=subject,
recipients=recipients,
body=body,
body=body + content,
)
return True


def send_email_to_event_participants(
yammesicka marked this conversation as resolved.
Show resolved Hide resolved
session: Session,
event_id: int,
title: str,
content: str,
user_logged: User = Depends(current_user),
) -> 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 != user_logged:
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,
Expand Down
39 changes: 23 additions & 16 deletions app/routers/email.py
Expand Up @@ -17,17 +17,20 @@

@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
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):
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)

Expand All @@ -44,8 +47,10 @@ class InvitationParams(BaseModel):


@router.post("/invitation/")
def send_invitation(invitation: InvitationParams,
background_task: BackgroundTasks):
def send_invitation(
invitation: InvitationParams,
background_task: BackgroundTasks,
):
"""
This function sends the recipient an invitation
to his email address in the format HTML.
Expand All @@ -60,12 +65,14 @@ def send_invitation(invitation: InvitationParams,
except EmailError:
raise HTTPException(
status_code=422,
detail=INVALID_EMAIL_ADDRESS_ERROR_MESSAGE)
detail=INVALID_EMAIL_ADDRESS_ERROR_MESSAGE,
)

if not send_email_invitation(
sender_name=invitation.sender_name,
recipient_name=invitation.recipient_name,
recipient_mail=invitation.recipient_mail,
background_tasks=background_task):
sender_name=invitation.sender_name,
recipient_name=invitation.recipient_name,
recipient_mail=invitation.recipient_mail,
background_tasks=background_task,
):
raise HTTPException(status_code=422, detail="Couldn't send the email!")
return RedirectResponse(invitation.send_to, status_code=303)
22 changes: 21 additions & 1 deletion app/routers/event.py
Expand Up @@ -41,7 +41,7 @@
)
from app.internal.privacy import PrivacyKinds
from app.internal.security.dependencies import current_user
from app.internal.utils import create_model, get_current_user
from app.internal.utils import create_model, get_current_user, save
from app.routers.categories import get_user_categories

IMAGE_HEIGHT = 200
Expand Down Expand Up @@ -488,6 +488,7 @@ def create_event(
longitude: Optional[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 Down Expand Up @@ -515,6 +516,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,
shared_list=shared_list,
Expand Down Expand Up @@ -617,6 +619,24 @@ 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 the user has a connection to the event,
# the function will recognize the duplicate and return false.

if user_already_connected:
return False
# 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


def extract_shared_list_from_data(
event_info: ImmutableMultiDict,
db: Session,
Expand Down
24 changes: 24 additions & 0 deletions tests/conftest.py
@@ -1,4 +1,5 @@
import calendar
from datetime import datetime

import nest_asyncio
import pytest
Expand All @@ -7,6 +8,7 @@

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

pytest_plugins = [
"tests.fixtures.user_fixture",
Expand Down Expand Up @@ -92,4 +94,26 @@ def Calendar():
return calendar.Calendar(0)


# the following fixtures are meant to replace user1, user2,user3
# fixtures inside test_user. they do the same but those have more indicative
# name, so after the feature freeze ill make sure to replace them completely.
# did not delete user1, user2 and user3 since some people
# use them in testing now.


@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


nest_asyncio.apply()
56 changes: 55 additions & 1 deletion tests/fixtures/user_fixture.py
@@ -1,3 +1,4 @@
from datetime import datetime
from typing import Generator

import pytest
Expand All @@ -6,7 +7,8 @@
from app.database.models import User
from app.database.schemas import UserCreate
from app.internal.utils import create_model, delete_instance
from app.routers.register import create_user
from app.routers.event import create_event
from app.routers.register import _create_user, create_user


@pytest.fixture
Expand Down Expand Up @@ -38,3 +40,55 @@ def sender(session: Session) -> Generator[User, None, None]:
)
yield mock_user
delete_instance(session, mock_user)


@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="new2_test.email@gmail.com",
language_id="english",
)

return user


@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="new_test_love231.email@gmail.com",
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


@pytest.fixture
def user1(session):
"""another user made for testing"""
user = _create_user(
session=session,
username="user2user2",
password="verynicepass",
email="trulyyours1.email@gmail.com",
language_id="english",
)
return user