Exemplo n.º 1
0
def test_user_display_last_active():
    assert User(last_active=datetime(2020, 7, 10, 16, 34, 1,
                                     1)).display_last_active == datetime(
                                         2020, 7, 10, 16, 0, 0, 0)
    assert User(last_active=datetime(2025, 7, 10, 17, 59, 1,
                                     1)).display_last_active == datetime(
                                         2025, 7, 10, 17, 0, 0, 0)
    assert User(last_active=datetime(2020, 7, 10, 16, 0, 1,
                                     1)).display_last_active == datetime(
                                         2020, 7, 10, 16, 0, 0, 0)
    assert User(last_active=datetime(2020, 7, 10, 0, 0, 0,
                                     0)).display_last_active == datetime(
                                         2020, 7, 10, 0, 0, 0, 0)
Exemplo n.º 2
0
def test_user_display_joined():
    assert User(
        joined=datetime(2020, 7, 10, 16, 34, 1, 1)).display_joined == datetime(
            2020, 7, 10, 16, 0, 0, 0)
    assert User(
        joined=datetime(2025, 7, 10, 16, 59, 1, 1)).display_joined == datetime(
            2025, 7, 10, 16, 0, 0, 0)
    assert User(
        joined=datetime(2020, 7, 10, 16, 0, 1, 1)).display_joined == datetime(
            2020, 7, 10, 16, 0, 0, 0)
    assert User(
        joined=datetime(2020, 7, 10, 0, 0, 0, 0)).display_joined == datetime(
            2020, 7, 10, 0, 0, 0, 0)
Exemplo n.º 3
0
def add_dummy_data(file_name):
    with session_scope(Session) as session:
        with open(file_name, "r") as file:
            users = json.loads(file.read())

        for user in users:
            new_user = User(
                username=user["username"],
                email=user["email"],
                hashed_password=hash_password(user["password"])
                if user["password"] else None,
                name=user["name"],
                city=user["city"],
                verification=user["verification"],
                community_standing=user["community_standing"],
                birthdate=date(year=user["birthdate"]["year"],
                               month=user["birthdate"]["month"],
                               day=user["birthdate"]["day"]),
                gender=user["gender"],
                languages="|".join(user["languages"]),
                occupation=user["occupation"],
                about_me=user["about_me"],
                about_place=user["about_place"],
                countries_visited="|".join(user["countries_visited"]),
                countries_lived="|".join(user["countries_lived"]),
            )
            session.add(new_user)
Exemplo n.º 4
0
    def CompleteSignup(self, request, context):
        """
        Completes user sign up by creating the user in question, then logs them in.

        TODO: nice error handling for dupe username/email?
        """
        with session_scope(self._Session) as session:
            signup_token = (
                session.query(SignupToken)
                .filter(SignupToken.token == request.signup_token)
                .filter(SignupToken.is_valid)
                .one_or_none()
            )
            if not signup_token:
                context.abort(grpc.StatusCode.NOT_FOUND, errors.INVALID_TOKEN)

            # should be in YYYY-MM-DD format
            try:
                birthdate = datetime.fromisoformat(request.birthdate)
            except ValueError:
                context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.INVALID_BIRTHDATE)

            # check email again
            if not is_valid_email(signup_token.email):
                context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.INVALID_EMAIL)

            # check username validity
            if not is_valid_username(request.username):
                context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.INVALID_USERNAME)

            # check name validity
            if not is_valid_name(request.name):
                context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.INVALID_NAME)

            if not request.hosting_status:
                context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.HOSTING_STATUS_REQUIRED)

            if not self._username_available(request.username):
                context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.USERNAME_NOT_AVAILABLE)

            user = User(
                email=signup_token.email,
                username=request.username,
                name=request.name,
                city=request.city,
                gender=request.gender,
                birthdate=birthdate,
                hosting_status=hostingstatus2sql[request.hosting_status],
            )

            # happens in same transaction
            session.delete(signup_token)

            # enforces email/username uniqueness
            session.add(user)
            session.commit()

            token = self._create_session(context, session, user)

            return auth_pb2.AuthRes(token=token, jailed=user.is_jailed)
Exemplo n.º 5
0
def generate_user(db, *_, **kwargs):
    """
    Create a new user, return session token

    The user is detached from any session, and you can access its static attributes, but you can't modify it

    Use this most of the time
    """
    auth = Auth(db)

    with session_scope(db) as session:
        # default args
        username = "******" + random_hex(16)
        user_opts = {
            "username": username,
            "email": f"{username}@dev.couchers.org",
            # password is just 'password'
            # this is hardcoded because the password is slow to hash (so would slow down tests otherwise)
            "hashed_password":
            b"$argon2id$v=19$m=65536,t=2,p=1$4cjGg1bRaZ10k+7XbIDmFg$tZG7JaLrkfyfO7cS233ocq7P8rf3znXR7SAfUt34kJg",
            "name": username.capitalize(),
            "city": "Testing city",
            "verification": 0.5,
            "community_standing": 0.5,
            "birthdate": date(year=2000, month=1, day=1),
            "gender": "N/A",
            "languages": "Testing language 1|Testing language 2",
            "occupation": "Tester",
            "about_me": "I test things",
            "about_place": "My place has a lot of testing paraphenelia",
            "countries_visited": "Testing country",
            "countries_lived": "Wonderland",
            # you need to make sure to update this logic to make sure the user is jailed/not on request
            "accepted_tos": 1,
        }

        for key, value in kwargs.items():
            user_opts[key] = value

        user = User(**user_opts)

        session.add(user)

        # this expires the user, so now it's "dirty"
        session.commit()

        token = auth._create_session("Dummy context", session, user)

        # refresh it, undoes the expiry
        session.refresh(user)
        # allows detaches the user from the session, allowing its use outside this session
        session.expunge(user)

    return user, token
Exemplo n.º 6
0
    def CompleteSignup(self, request, context):
        """
        Completes user sign up by creating the user in question, then logs them in.

        TODO: nice error handling for dupe username/email?
        """
        with session_scope(self._Session) as session:
            signup_token = session.query(SignupToken) \
                .filter(SignupToken.token == request.signup_token) \
                .filter(SignupToken.created <= func.now()) \
                .filter(SignupToken.expiry >= func.now()) \
                .one_or_none()
            if not signup_token:
                context.abort(grpc.StatusCode.NOT_FOUND, "Invalid token.")

            # should be in YYYY/MM/DD format, will raise exception if can't parse
            birthdate = datetime.fromisoformat(request.birthdate)

            # check email again
            if not is_valid_email(signup_token.email):
                context.abort(grpc.StatusCode.INVALID_ARGUMENT, "Invalid email")

            # check username validity
            if not is_valid_username(request.username):
                context.abort(grpc.StatusCode.INVALID_ARGUMENT, "Invalid username")

            user = User(
                email=signup_token.email,
                username=request.username,
                name=request.name,
                city=request.city,
                gender=request.gender,
                birthdate=birthdate
            )

            # happens in same transaction
            session.delete(signup_token)

            # enforces email/username uniqueness
            session.add(user)
            session.commit()

            token = self._create_session(session, user)

            return auth_pb2.AuthRes(token=token)
Exemplo n.º 7
0
    def CompleteSignup(self, request, context):
        """
        Completes user sign up by creating the user in question, then logs them in.

        TODO: nice error handling for dupe username/email?
        """
        with session_scope() as session:
            signup_token = (
                session.query(SignupToken)
                .filter(SignupToken.token == request.signup_token)
                .filter(SignupToken.is_valid)
                .one_or_none()
            )
            if not signup_token:
                context.abort(grpc.StatusCode.NOT_FOUND, errors.INVALID_TOKEN)

            # check birthdate validity (YYYY-MM-DD format and in the past)
            try:
                birthdate = datetime.fromisoformat(request.birthdate)
            except ValueError:
                context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.INVALID_BIRTHDATE)
            if pytz.UTC.localize(birthdate) >= now():
                context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.INVALID_BIRTHDATE)

            # check email again
            if not is_valid_email(signup_token.email):
                context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.INVALID_EMAIL)

            # check username validity
            if not is_valid_username(request.username):
                context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.INVALID_USERNAME)

            # check name validity
            if not is_valid_name(request.name):
                context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.INVALID_NAME)

            if not request.hosting_status:
                context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.HOSTING_STATUS_REQUIRED)

            if not self._username_available(request.username):
                context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.USERNAME_NOT_AVAILABLE)

            if request.lat == 0 and request.lng == 0:
                context.abort(grpc.StatusCode.INVALID_ARGUMENT, errors.INVALID_COORDINATE)

            user = User(
                email=signup_token.email,
                username=request.username,
                name=request.name,
                gender=request.gender,
                birthdate=birthdate,
                hosting_status=hostingstatus2sql[request.hosting_status],
                city=request.city,
                geom=create_coordinate(request.lat, request.lng),
                geom_radius=request.radius,
                accepted_tos=1 if request.accept_tos else 0,
            )

            # happens in same transaction
            session.delete(signup_token)

            # enforces email/username uniqueness
            session.add(user)
            session.commit()

            token, expiry = self._create_session(context, session, user, False)
            context.send_initial_metadata(
                [
                    ("set-cookie", create_session_cookie(token, expiry)),
                ]
            )
            return auth_pb2.AuthRes(jailed=user.is_jailed)
Exemplo n.º 8
0
def add_dummy_users():
    try:
        logger.info(f"Adding dummy users")
        with session_scope() as session:
            with open("src/data/dummy_users.json", "r") as file:
                data = json.loads(file.read())

            for user in data["users"]:
                new_user = User(
                    username=user["username"],
                    email=user["email"],
                    hashed_password=hash_password(user["password"])
                    if user["password"] else None,
                    name=user["name"],
                    city=user["location"]["city"],
                    geom=create_coordinate(user["location"]["lat"],
                                           user["location"]["lng"]),
                    geom_radius=user["location"]["radius"],
                    verification=user["verification"],
                    community_standing=user["community_standing"],
                    birthdate=date(year=user["birthdate"]["year"],
                                   month=user["birthdate"]["month"],
                                   day=user["birthdate"]["day"]),
                    gender=user["gender"],
                    languages="|".join(user["languages"]),
                    occupation=user["occupation"],
                    about_me=user["about_me"],
                    about_place=user["about_place"],
                    countries_visited="|".join(user["countries_visited"]),
                    countries_lived="|".join(user["countries_lived"]),
                    hosting_status=hostingstatus2sql[HostingStatus.Value(
                        user["hosting_status"])]
                    if "hosting_status" in user else None,
                )
                session.add(new_user)

            session.commit()

            for username1, username2 in data["friendships"]:
                friend_relationship = FriendRelationship(
                    from_user_id=get_user_by_field(session, username1).id,
                    to_user_id=get_user_by_field(session, username2).id,
                    status=FriendStatus.accepted,
                )
                session.add(friend_relationship)

            session.commit()

            for reference in data["references"]:
                reference_type = (ReferenceType.HOSTED
                                  if reference["type"] == "hosted" else
                                  (ReferenceType.SURFED if reference["type"]
                                   == "surfed" else ReferenceType.FRIEND))
                new_reference = Reference(
                    from_user_id=get_user_by_field(session,
                                                   reference["from"]).id,
                    to_user_id=get_user_by_field(session, reference["to"]).id,
                    reference_type=reference_type,
                    text=reference["text"],
                    rating=reference["rating"],
                    was_safe=reference["was_safe"],
                )
                session.add(new_reference)

            session.commit()

            for group_chat in data["group_chats"]:
                # Create the chat
                creator = group_chat["creator"]

                conversation = Conversation()
                session.add(conversation)

                chat = GroupChat(
                    conversation=conversation,
                    title=group_chat["title"],
                    creator_id=get_user_by_field(session, creator).id,
                    is_dm=group_chat["is_dm"],
                )
                session.add(chat)

                for participant in group_chat["participants"]:
                    subscription = GroupChatSubscription(
                        user_id=get_user_by_field(session,
                                                  participant["username"]).id,
                        group_chat=chat,
                        role=GroupChatRole.admin if participant["username"]
                        == creator else GroupChatRole.participant,
                        joined=parser.isoparse(participant["joined"]),
                    )
                    session.add(subscription)

                for message in group_chat["messages"]:
                    session.add(
                        Message(
                            message_type=MessageType.text,
                            conversation=chat.conversation,
                            author_id=get_user_by_field(
                                session, message["author"]).id,
                            time=parser.isoparse(message["time"]),
                            text=message["message"],
                        ))

            session.commit()

    except IntegrityError:
        logger.error("Failed to insert dummy users, is it already inserted?")
Exemplo n.º 9
0
def test_user_birthdate():
    FakeDate.today = classmethod(lambda cls: date(2019, 7, 5))
    assert User(birthdate = date(1990, 7, 4)).age == 29
    assert User(birthdate = date(1990, 7, 31)).age == 28
    assert User(birthdate = date(1992, 2, 29)).age == 27
Exemplo n.º 10
0
    def SignupFlow(self, request, context):
        with session_scope() as session:
            if request.email_token:
                # the email token can either be for verification or just to find an existing signup
                flow = session.execute(
                    select(SignupFlow).
                    where(SignupFlow.email_verified == False).where(
                        SignupFlow.email_token == request.email_token).where(
                            SignupFlow.token_is_valid)).scalar_one_or_none()
                if flow:
                    # find flow by email verification token and mark it as verified
                    flow.email_verified = True
                    flow.email_token = None
                    flow.email_token_expiry = None

                    session.flush()
                else:
                    # just try to find the flow by flow token, no verification is done
                    flow = session.execute(
                        select(SignupFlow).where(
                            SignupFlow.flow_token ==
                            request.email_token)).scalar_one_or_none()
                    if not flow:
                        context.abort(grpc.StatusCode.NOT_FOUND,
                                      errors.INVALID_TOKEN)
            else:
                if not request.flow_token:
                    # fresh signup
                    if not request.HasField("basic"):
                        context.abort(grpc.StatusCode.INVALID_ARGUMENT,
                                      errors.SIGNUP_FLOW_BASIC_NEEDED)
                    # TODO: unique across both tables
                    existing_user = session.execute(
                        select(User).where(User.email == request.basic.email)
                    ).scalar_one_or_none()
                    if existing_user:
                        context.abort(grpc.StatusCode.FAILED_PRECONDITION,
                                      errors.SIGNUP_FLOW_EMAIL_TAKEN)
                    existing_flow = session.execute(
                        select(SignupFlow).where(
                            SignupFlow.email ==
                            request.basic.email)).scalar_one_or_none()
                    if existing_flow:
                        send_signup_email(existing_flow)
                        session.commit()
                        context.abort(grpc.StatusCode.FAILED_PRECONDITION,
                                      errors.SIGNUP_FLOW_EMAIL_STARTED_SIGNUP)

                    if not is_valid_email(request.basic.email):
                        context.abort(grpc.StatusCode.INVALID_ARGUMENT,
                                      errors.INVALID_EMAIL)
                    if not is_valid_name(request.basic.name):
                        context.abort(grpc.StatusCode.INVALID_ARGUMENT,
                                      errors.INVALID_NAME)

                    flow_token = cookiesafe_secure_token()

                    flow = SignupFlow(
                        flow_token=flow_token,
                        name=request.basic.name,
                        email=request.basic.email,
                    )
                    session.add(flow)
                    session.flush()
                else:
                    # not fresh signup
                    flow = session.execute(
                        select(SignupFlow).where(
                            SignupFlow.flow_token ==
                            request.flow_token)).scalar_one_or_none()
                    if not flow:
                        context.abort(grpc.StatusCode.NOT_FOUND,
                                      errors.INVALID_TOKEN)
                    if request.HasField("basic"):
                        context.abort(grpc.StatusCode.FAILED_PRECONDITION,
                                      errors.SIGNUP_FLOW_BASIC_FILLED)

                # we've found and/or created a new flow, now sort out other parts
                if request.HasField("account"):
                    if flow.account_is_filled:
                        context.abort(grpc.StatusCode.FAILED_PRECONDITION,
                                      errors.SIGNUP_FLOW_ACCOUNT_FILLED)

                    # check username validity
                    if not is_valid_username(request.account.username):
                        context.abort(grpc.StatusCode.INVALID_ARGUMENT,
                                      errors.INVALID_USERNAME)

                    if not self._username_available(request.account.username):
                        context.abort(grpc.StatusCode.FAILED_PRECONDITION,
                                      errors.USERNAME_NOT_AVAILABLE)

                    abort_on_invalid_password(request.account.password,
                                              context)
                    hashed_password = hash_password(request.account.password)

                    birthdate = parse_date(request.account.birthdate)
                    if not birthdate or birthdate >= minimum_allowed_birthdate(
                    ):
                        context.abort(grpc.StatusCode.FAILED_PRECONDITION,
                                      errors.INVALID_BIRTHDATE)

                    if not request.account.hosting_status:
                        context.abort(grpc.StatusCode.INVALID_ARGUMENT,
                                      errors.HOSTING_STATUS_REQUIRED)

                    if request.account.lat == 0 and request.account.lng == 0:
                        context.abort(grpc.StatusCode.INVALID_ARGUMENT,
                                      errors.INVALID_COORDINATE)

                    if not request.account.accept_tos:
                        context.abort(grpc.StatusCode.INVALID_ARGUMENT,
                                      errors.MUST_ACCEPT_TOS)

                    flow.username = request.account.username
                    flow.hashed_password = hashed_password
                    flow.birthdate = birthdate
                    flow.gender = request.account.gender
                    flow.hosting_status = hostingstatus2sql[
                        request.account.hosting_status]
                    flow.city = request.account.city
                    flow.geom = create_coordinate(request.account.lat,
                                                  request.account.lng)
                    flow.geom_radius = request.account.radius
                    flow.accepted_tos = TOS_VERSION
                    session.flush()

                if request.HasField("feedback"):
                    if flow.filled_feedback:
                        context.abort(grpc.StatusCode.FAILED_PRECONDITION,
                                      errors.SIGNUP_FLOW_FEEDBACK_FILLED)
                    form = request.feedback

                    flow.filled_feedback = True
                    flow.ideas = form.ideas
                    flow.features = form.features
                    flow.experience = form.experience
                    flow.contribute = contributeoption2sql[form.contribute]
                    flow.contribute_ways = form.contribute_ways
                    flow.expertise = form.expertise
                    session.flush()

                if request.HasField("accept_community_guidelines"):
                    if not request.accept_community_guidelines.value:
                        context.abort(grpc.StatusCode.INVALID_ARGUMENT,
                                      errors.MUST_ACCEPT_COMMUNITY_GUIDELINES)
                    flow.accepted_community_guidelines = GUIDELINES_VERSION
                    session.flush()

                # send verification email if needed
                if not flow.email_sent:
                    send_signup_email(flow)

                session.flush()

            # finish the signup if done
            if flow.is_completed:
                user = User(
                    name=flow.name,
                    email=flow.email,
                    username=flow.username,
                    hashed_password=flow.hashed_password,
                    birthdate=flow.birthdate,
                    gender=flow.gender,
                    hosting_status=flow.hosting_status,
                    city=flow.city,
                    geom=flow.geom,
                    geom_radius=flow.geom_radius,
                    accepted_tos=flow.accepted_tos,
                    accepted_community_guidelines=flow.
                    accepted_community_guidelines,
                    onboarding_emails_sent=1,
                    last_onboarding_email_sent=func.now(),
                )

                session.add(user)

                form = ContributorForm(
                    user=user,
                    ideas=flow.ideas or None,
                    features=flow.features or None,
                    experience=flow.experience or None,
                    contribute=flow.contribute or None,
                    contribute_ways=flow.contribute_ways,
                    expertise=flow.expertise or None,
                )

                session.add(form)

                user.filled_contributor_form = form.is_filled

                session.delete(flow)
                session.commit()

                enforce_community_memberships_for_user(session, user)

                if form.is_filled:
                    user.filled_contributor_form = True

                maybe_send_contributor_form_email(form)

                send_onboarding_email(user, email_number=1)

                token, expiry = create_session(context, session, user, False)
                context.send_initial_metadata([
                    ("set-cookie", create_session_cookie(token, expiry)),
                ])
                return auth_pb2.SignupFlowRes(auth_res=_auth_res(user), )
            else:
                return auth_pb2.SignupFlowRes(
                    flow_token=flow.flow_token,
                    need_account=not flow.account_is_filled,
                    need_feedback=not flow.filled_feedback,
                    need_verify_email=not flow.email_verified,
                    need_accept_community_guidelines=flow.
                    accepted_community_guidelines < GUIDELINES_VERSION,
                )
Exemplo n.º 11
0
def add_dummy_users():
    logger.info(f"Adding dummy users")
    with session_scope() as session:
        if session.execute(select(
                func.count()).select_from(User)).scalar_one() > 0:
            logger.info("Users not empty, not adding dummy users")
            return

        with open(SRC_DIR + "/data/dummy_users.json", "r") as f:
            data = json.loads(f.read())

        for user in data["users"]:
            new_user = User(
                username=user["username"],
                email=user["email"],
                hashed_password=hash_password(user["password"])
                if user["password"] else None,
                name=user["name"],
                city=user["location"]["city"],
                geom=create_coordinate(user["location"]["lat"],
                                       user["location"]["lng"]),
                geom_radius=user["location"]["radius"],
                community_standing=user["community_standing"],
                birthdate=date(year=user["birthdate"]["year"],
                               month=user["birthdate"]["month"],
                               day=user["birthdate"]["day"]),
                gender=user["gender"],
                occupation=user["occupation"],
                about_me=user["about_me"],
                about_place=user["about_place"],
                hosting_status=hostingstatus2sql[HostingStatus.Value(
                    user["hosting_status"] if "hosting_status" in
                    user else "HOSTING_STATUS_CANT_HOST")],
                new_notifications_enabled=True,
                accepted_tos=TOS_VERSION,
                accepted_community_guidelines=GUIDELINES_VERSION,
            )
            session.add(new_user)
            session.flush()

            for language in user["languages"]:
                session.add(
                    LanguageAbility(user_id=new_user.id,
                                    language_code=language[0],
                                    fluency=LanguageFluency[language[1]]))
            for region in user["regions_visited"]:
                session.add(
                    RegionVisited(user_id=new_user.id, region_code=region))
            for region in user["regions_lived"]:
                session.add(
                    RegionLived(user_id=new_user.id, region_code=region))

        session.commit()

        for username1, username2 in data["friendships"]:
            friend_relationship = FriendRelationship(
                from_user_id=session.execute(
                    select(User).where(
                        User.username == username1)).scalar_one().id,
                to_user_id=session.execute(
                    select(User).where(
                        User.username == username2)).scalar_one().id,
                status=FriendStatus.accepted,
            )
            session.add(friend_relationship)

        session.commit()

        for reference in data["references"]:
            reference_type = (ReferenceType.hosted
                              if reference["type"] == "hosted" else
                              (ReferenceType.surfed if reference["type"]
                               == "surfed" else ReferenceType.friend))
            new_reference = Reference(
                from_user_id=session.execute(
                    select(User).where(
                        User.username == reference["from"])).scalar_one().id,
                to_user_id=session.execute(
                    select(User).where(
                        User.username == reference["to"])).scalar_one().id,
                reference_type=reference_type,
                text=reference["text"],
                rating=reference["rating"],
                was_appropriate=reference["was_appropriate"],
            )
            session.add(new_reference)

        session.commit()

        for group_chat in data["group_chats"]:
            # Create the chat
            creator = group_chat["creator"]

            conversation = Conversation()
            session.add(conversation)

            chat = GroupChat(
                conversation=conversation,
                title=group_chat["title"],
                creator_id=session.execute(
                    select(User).where(
                        User.username == creator)).scalar_one().id,
                is_dm=group_chat["is_dm"],
            )
            session.add(chat)

            for participant in group_chat["participants"]:
                subscription = GroupChatSubscription(
                    user_id=session.execute(
                        select(User).where(
                            User.username ==
                            participant["username"])).scalar_one().id,
                    group_chat=chat,
                    role=GroupChatRole.admin if participant["username"]
                    == creator else GroupChatRole.participant,
                    joined=parser.isoparse(participant["joined"]),
                )
                session.add(subscription)

            for message in group_chat["messages"]:
                session.add(
                    Message(
                        message_type=MessageType.text,
                        conversation=chat.conversation,
                        author_id=session.execute(
                            select(User).where(
                                User.username ==
                                message["author"])).scalar_one().id,
                        time=parser.isoparse(message["time"]),
                        text=message["message"],
                    ))

        session.commit()