def accept_friend_request(self, from_user_email: str,
                              to_user_email: str) -> NoReturn:
        """
        Accepts an existing friend request

        :raises:
            UnexistentFriendRequest: the friend request does not exist or is not pending

        :param from_user_email: the user that requested the friendship
        :param to_user_email: the target user of the request
        """
        if from_user_email not in self.get_friend_requests(to_user_email):
            raise UnexistentFriendRequest
        cursor = self.conn.cursor()
        PostgresUtils.safe_query_run(
            self.logger, self.conn, cursor,
            DELETE_FRIEND_REQUEST_QUERY.format(
                self.friend_requests_table_name),
            (from_user_email, to_user_email))
        self.conn.commit()

        friend_tuple = list(sorted([from_user_email, to_user_email]))
        friend_tuple = (friend_tuple[0], friend_tuple[1])
        cursor.execute(NEW_FRIENDS_QUERY.format(self.friends_table_name),
                       friend_tuple)
        self.conn.commit()

        cursor.close()
    def last_days_api_calls(self,
                            days: int) -> Generator[List[ApiCall], None, None]:
        """
        Gets a generator of the last days api calls

        :param days: the number of days back
        :return: a generator of lists of api calls
        """
        cursor = self.conn.cursor()

        PostgresUtils.safe_query_run(
            self.logger, self.conn, cursor,
            COUNT_ROWS_API_CALLS_QUERY.format(
                app_server_api_calls_table=self.app_server_api_calls_table),
            (days, ))
        result = cursor.fetchone()

        pages = int(math.ceil(result[0] / DEFAULT_BATCH_SIZE))
        for page in range(pages):
            PostgresUtils.safe_query_run(
                self.logger, self.conn, cursor,
                GET_PAGINATED_API_CALLS_QUERY.format(
                    app_server_api_calls_table=self.app_server_api_calls_table
                ), (days, DEFAULT_BATCH_SIZE, page * DEFAULT_BATCH_SIZE))
            result = cursor.fetchall()
            # path, status, datetime, "time", method
            yield [
                ApiCall(path=r[0],
                        status=r[1],
                        timestamp=r[2],
                        time=r[3],
                        method=r[4]) for r in result
            ]
    def get_conversation(self, requestor_email: str, other_user_email: str,
                         per_page: int,
                         page: int) -> Tuple[List[PrivateMessage], int]:
        """
        Get the paginated conversation between user1 and user2

        :raises:
            NoMoreMessagesError: the page has no messages

        :param requestor_email: the email of user1
        :param other_user_email: the email of user2
        :param per_page: the messages per page
        :param page: the page for the message, starting from 0
        :return: the list of private messages and the number of pages
        """
        self.logger.debug("Geting conversation between %s and %s" %
                          (requestor_email, other_user_email))

        cursor = self.conn.cursor()

        PostgresUtils.safe_query_run(
            self.logger, self.conn, cursor,
            COUNT_ROWS_CONVERSATION_QUERY.format(
                user_messages_table_name=self.user_messages_table_name,
                user_deleted_messages_table_name=self.
                user_deleted_messages_table_name),
            (requestor_email, other_user_email, requestor_email,
             other_user_email, requestor_email))
        result = cursor.fetchone()

        pages = int(math.ceil(result[0] / per_page))
        if not page < pages and page != 0:
            raise NoMoreMessagesError()

        PostgresUtils.safe_query_run(
            self.logger, self.conn, cursor,
            GET_PAGINATED_CONVERSATION_QUERY.format(
                user_messages_table_name=self.user_messages_table_name,
                user_deleted_messages_table_name=self.
                user_deleted_messages_table_name),
            (requestor_email, other_user_email, requestor_email,
             other_user_email, requestor_email, per_page, page * per_page))
        result = cursor.fetchall()
        self.conn.commit()
        cursor.close()
        # from_user, to_user, message, datetime
        result = [
            PrivateMessage(from_user=r[0],
                           to_user=r[1],
                           message=r[2],
                           timestamp=r[3]) for r in result
        ]
        return result, pages
    def register_api_call(self, api_call: ApiCall) -> NoReturn:
        """
        Registers an api call

        :param api_call: the api call to register
        """
        cursor = self.conn.cursor()
        PostgresUtils.safe_query_run(
            self.logger, self.conn, cursor,
            ADD_API_CALL_QUERY.format(
                app_server_api_calls_table=self.app_server_api_calls_table),
            (self.server_alias, api_call.path, api_call.status,
             api_call.timestamp.isoformat(), api_call.time, api_call.method))
        self.conn.commit()
        cursor.close()
    def get_friend_requests(self, user_email: str) -> List[str]:
        """
        Gets all the user emails that have sent a user request to the user

        :param user_email: the user to query for its friend requests
        :return: a list of emails
        """
        self.logger.debug("Getting friend requests for %s" % user_email)
        cursor = self.conn.cursor()
        PostgresUtils.safe_query_run(
            self.logger, self.conn, cursor,
            FRIEND_REQUEST_QUERY.format(self.friend_requests_table_name) %
            user_email)
        result = cursor.fetchall()
        cursor.close()
        return [r[0] for r in result]
    def get_friends(self, user_email: str) -> List[str]:
        """
        Gets all the user emails that are friends of the user

        :param user_email: the user to query for its friend
        :return: a list of emails
        """
        self.logger.debug("Getting friends for %s" % user_email)
        cursor = self.conn.cursor()
        PostgresUtils.safe_query_run(
            self.logger, self.conn, cursor,
            ALL_FRIENDS_QUERY.format(self.friends_table_name) %
            (user_email, user_email))
        result = cursor.fetchall()
        cursor.close()
        friend_emails = [t[0] for t in result] + [t[1] for t in result]
        return [f for f in friend_emails if f != user_email]
    def delete_friendship(self, user_email1: str,
                          user_email2: str) -> NoReturn:
        """
        Delete friendship if exists

        :param user_email1: first user email
        :param user_email2: second user email
        """
        friend_tuple = list(sorted([user_email1, user_email2]))
        friend_tuple = (friend_tuple[0], friend_tuple[1])
        self.logger.debug("Deleting friendship between %s and %s" %
                          (user_email1, user_email2))
        cursor = self.conn.cursor()
        PostgresUtils.safe_query_run(
            self.logger, self.conn, cursor,
            DELETE_FRIEND_QUERY.format(self.friends_table_name), friend_tuple)
        cursor.close()
        self.conn.commit()
예제 #8
0
    def notify(self, user_email: str, title: str, body: str,
               payload: Dict) -> NoReturn:
        """
        Sends the payload a notification the the user if has registered an app token for that user

        :param user_email: the user email for sending the payload
        :param title: the title of the notification
        :param body: the body of the notification
        :param payload: the payload to send
        """
        self.logger.debug("Sending notification to %s" % user_email)
        cursor = self.conn.cursor()
        try:
            PostgresUtils.safe_query_run(
                self.logger, self.conn, cursor,
                SEARCH_NOTIFICATION_TOKEN.format(
                    notification_tokens_table_name=self.
                    notification_tokens_table_name), (user_email, ))
            result = cursor.fetchone()
        except Exception:
            self.logger.exception("Couldn't send notification")
            cursor.close()
            return
        if result:
            token = result[0]
            cursor.close()
        else:
            cursor.close()
            return
        try:
            r = requests.post(EXPO_SEND_NOTIFICATION_ENDPOINT,
                              json={
                                  "to": token,
                                  "title": title,
                                  "body": body,
                                  "data": payload
                              },
                              timeout=NOTIFICATION_SEND_TIMEOUT)
            r.raise_for_status()
        except Exception:
            self.logger.exception("Couldn't send notification")
            return
예제 #9
0
    def set_notification_token(self, user_email: str, token: str) -> NoReturn:
        """
        Sets the notification token for a user email

        :param user_email: the user email for setting the notification token
        :param token: the token to set
        """
        self.logger.debug("Setting notification token for %s" % user_email)
        cursor = self.conn.cursor()
        try:
            PostgresUtils.safe_query_run(
                self.logger, self.conn, cursor,
                NOTIFICATION_TOKEN_SAVE.format(
                    notification_tokens_table_name=self.
                    notification_tokens_table_name),
                (token, user_email, token))
        except Exception:
            self.logger.exception("Couldn't register notification token")
        self.conn.commit()
        cursor.close()
    def are_friends(self, user_email1: str, user_email2: str) -> bool:
        """
        Check if user1 is friend with user2

        :param user_email1: the first user email
        :param user_email2: the second user email
        :return: a boolean indicating whether user1 is friend user2's friend
        """
        self.logger.debug("Checking whether %s and %s are friends" %
                          (user_email1, user_email2))
        cursor = self.conn.cursor()
        friends_ordered = tuple(list(sorted([user_email1, user_email2])))
        PostgresUtils.safe_query_run(
            self.logger, self.conn, cursor,
            CHECK_FRIENDS_QUERY.format(self.friends_table_name) %
            friends_ordered)
        result = cursor.fetchone()
        cursor.close()
        if not result:
            return False
        return True
    def delete_conversation(self, deletor_email: str,
                            deleted_email: str) -> NoReturn:
        """
        Deletes the conversation between two users but just for the deletor

        :param deletor_email: the email of the one that deletes the conversation
        :param deleted_email: the email of the other user of the conversation
        """
        self.logger.debug("%s deleting conversation with %s" %
                          (deletor_email, deleted_email))
        cursor = self.conn.cursor()
        PostgresUtils.safe_query_run(
            self.logger, self.conn, cursor,
            DELETE_CONVERSATION_QUERY.format(
                user_messages_table_name=self.user_messages_table_name,
                user_deleted_messages_table_name=self.
                user_deleted_messages_table_name),
            (deletor_email, deletor_email, deleted_email, deletor_email,
             deleted_email, deletor_email))
        self.conn.commit()
        cursor.close()
    def exists_friend_request(self, from_user_email: str,
                              to_user_email: str) -> bool:
        """
        Check if exists friend request from 'requestor' to 'receiver'

        :param from_user_email: the requestor of the friendship
        :param to_user_email: the receiver of the request
        :return: a boolean indicating whether the friend request exists
        """
        self.logger.debug("Checking whether %s sent a friend request to %s" %
                          (from_user_email, to_user_email))
        cursor = self.conn.cursor()
        PostgresUtils.safe_query_run(
            self.logger, self.conn, cursor,
            CHECK_FRIEND_REQUEST_QUERY.format(self.friend_requests_table_name),
            (from_user_email, to_user_email))
        result = cursor.fetchone()
        cursor.close()
        if not result:
            return False
        return True
    def technical_metrics_from_server(self, alias: str) -> TechnicalMetrics:
        """
        Get technical metrics from a particular server

        :raises:
            UnexistentAppServer: if the alias is not associated with an app server

        :param alias: the alias of the app server
        :return: the technical metrics
        """
        cursor = self.conn.cursor()
        stats = {"total": 0, 400: 0, 500: 0, "mean_time": 0.0}
        PostgresUtils.safe_query_run(
            self.logger, self.conn, cursor,
            GET_CALS_BY_STATUS_QUERY.format(
                app_server_api_calls_table=self.app_server_api_calls_table),
            (7, alias))
        result = cursor.fetchall()
        if not result:
            raise UnexistentAppServer
        for r in result:
            stats["total"] += r[1]
            if r[0] == 400:
                stats[400] = r[1]
            if r[0] == 500:
                stats[500] = r[1]
        PostgresUtils.safe_query_run(
            self.logger, self.conn, cursor,
            GET_MEAN_RESPONSE_TIMES_QUERY.format(
                app_server_api_calls_table=self.app_server_api_calls_table),
            (7, alias))
        result = cursor.fetchall()
        for r in result:
            stats["mean_time"] = r[0]
        cursor.close()
        return TechnicalMetrics(
            mean_response_time_last_7_days=stats["mean_time"],
            api_calls_last_7_days=stats["total"],
            status_500_rate_last_7_days=stats[500] / stats["total"],
            status_400_rate_last_7_days=stats[400] / stats["total"])
    def get_conversations(
            self, user_email: str) -> Tuple[List[Dict], List[PrivateMessage]]:
        """
        Get all the conversations ordered by recent activity

        :param user_email: the email of the user for getting the conversations
        :return: a tuple (list of user data, list of last private message)
        """
        self.logger.debug("Geting last conversations with %s" % user_email)

        cursor = self.conn.cursor()
        PostgresUtils.safe_query_run(
            self.logger, self.conn, cursor,
            GET_CONVERSATIONS_QUERY.format(
                friends_table_name=self.friends_table_name,
                user_messages_table_name=self.user_messages_table_name,
                users_table_name=self.users_table_name,
                user_deleted_messages_table_name=self.
                user_deleted_messages_table_name), (user_email, ) * 9)
        '''
        u.email, u.fullname, u.phone_number, u.photo
        messages.from_user, messages.to_user, messages.message, messages.datetime
        '''
        result = cursor.fetchall()
        user_data = [{
            "email": r[0],
            "fullname": r[1],
            "phone_number": r[2],
            "photo": r[3]
        } for r in result]
        videos_data = [
            PrivateMessage(from_user=r[4],
                           to_user=r[5],
                           message=r[6],
                           timestamp=r[7]) for r in result
        ]
        self.conn.commit()
        cursor.close()
        return user_data, videos_data
예제 #15
0
 def __init__(self, notification_tokens_table_name: str,
              postgr_host_env_name: str, postgr_user_env_name: str,
              postgr_pass_env_name: str, postgr_database_env_name: str):
     self.notification_tokens_table_name = notification_tokens_table_name
     self.conn = PostgresUtils.get_postgres_connection(
         host=os.environ[postgr_host_env_name],
         user=os.environ[postgr_user_env_name],
         password=os.environ[postgr_pass_env_name],
         database=os.environ[postgr_database_env_name])
     if self.conn.closed == 0:
         self.logger.info("Connected to postgres database")
     else:
         self.logger.error("Unable to connect to postgres database")
         raise ConnectionError("Unable to connect to postgres database")
    def send_message(self, from_user_email: str, to_user_email: str,
                     message: str) -> NoReturn:
        """
        Sends a private message to a user

        :raises:
            UsersAreNotFriendsError: the users are not friends

        :param from_user_email: the email of the sender
        :param to_user_email: the email of the receiver
        :param message: the message to send
        """
        if not self.are_friends(from_user_email, to_user_email):
            raise UsersAreNotFriendsError
        self.logger.debug("Sending user message")
        cursor = self.conn.cursor()
        PostgresUtils.safe_query_run(
            self.logger, self.conn, cursor,
            SEND_MESSAGE_QUERY.format(self.user_messages_table_name),
            (from_user_email, to_user_email, message,
             datetime.now().isoformat()))
        self.conn.commit()
        cursor.close()
    def create_friend_request(self, from_user_email: str,
                              to_user_email: str) -> NoReturn:
        """
        Creates a friend request between

        :raises:
            UsersAlreadyFriendsError: raised when the users are already friends
            UnexistentTargetUserError: the target user does not exist
            UnexistentRequestorUserError: the user that requested the friendship does not exist

        :param from_user_email: the user that requests the friendship
        :param to_user_email: the target user of the request
        """
        if self.are_friends(from_user_email, to_user_email):
            raise UsersAlreadyFriendsError
        self.logger.debug("Sending friend request for user with email %s" %
                          from_user_email)
        cursor = self.conn.cursor()
        PostgresUtils.safe_query_run(
            self.logger, self.conn, cursor,
            NEW_FRIEND_REQUEST_QUERY.format(self.friend_requests_table_name),
            (from_user_email, to_user_email, datetime.now().isoformat()))
        self.conn.commit()
        cursor.close()
    def __init__(self, app_server_api_calls_table: str,
                 server_alias_env_name: str, postgr_host_env_name: str,
                 postgr_user_env_name: str, postgr_pass_env_name: str,
                 postgr_database_env_name: str):

        self.app_server_api_calls_table = app_server_api_calls_table
        self.server_alias = os.environ[server_alias_env_name]
        self.conn = PostgresUtils.get_postgres_connection(
            host=os.environ[postgr_host_env_name],
            user=os.environ[postgr_user_env_name],
            password=os.environ[postgr_pass_env_name],
            database=os.environ[postgr_database_env_name])
        if self.conn.closed == 0:
            self.logger.info("Connected to postgres database")
        else:
            self.logger.error("Unable to connect to postgres database")
            raise ConnectionError("Unable to connect to postgres database")
    def __init__(self, friends_table_name: str,
                 friend_requests_table_name: str,
                 user_messages_table_name: str, users_table_name: str,
                 user_deleted_messages_table_name: str,
                 postgr_host_env_name: str, postgr_user_env_name: str,
                 postgr_pass_env_name: str, postgr_database_env_name: str):

        self.friends_table_name = friends_table_name
        self.friend_requests_table_name = friend_requests_table_name
        self.user_messages_table_name = user_messages_table_name
        self.users_table_name = users_table_name
        self.user_deleted_messages_table_name = user_deleted_messages_table_name
        self.conn = PostgresUtils.get_postgres_connection(
            host=os.environ[postgr_host_env_name],
            user=os.environ[postgr_user_env_name],
            password=os.environ[postgr_pass_env_name],
            database=os.environ[postgr_database_env_name])
        if self.conn.closed == 0:
            self.logger.info("Connected to postgres database")
        else:
            self.logger.error("Unable to connect to postgres database")
            raise ConnectionError("Unable to connect to postgres database")