Ejemplo n.º 1
0
 def test_get_credentials(self):
     """
     Tests credential property method as well as set_credentials
     """
     with Database(DB) as db:
         db.set_credentials('a.potts.bot', 'sample_password', 'mellandru')
         self.assertEqual(('a.potts.bot', 'sample_password', 'mellandru'),
                          db.credentials)
         db.set_credentials('a', 'b', 'c')
         self.assertEqual(('a', 'b', 'c'), db.credentials)
Ejemplo n.º 2
0
 def test_get_hits(self) -> None:
     """
     Confirms that the fetch searches method works as expected
     """
     with Database(DB) as db:
         db.add_search('google.com', 'test_name')
         self.assertEqual([], db.get_hits('google.com'))
         db.cursor.execute('UPDATE searches SET hits = ? WHERE url = ?',
                           ('hello,friend', 'google.com'))
         self.assertEqual(['hello', 'friend'], db.get_hits('google.com'))
Ejemplo n.º 3
0
 def test_get_url_name(self) -> None:
     """
     Tests getting name / URLs from database
     """
     with Database(DB) as db:
         db.add_search(URL, 'test_name')
         db.add_search('youtube', 'asdf')
         db.add_search('4chan', 'cuck')
         res = db.get_url_name()
         self.assertEqual([(URL, 'test_name'), ('youtube', 'asdf'),
                           ('4chan', 'cuck')], res)
Ejemplo n.º 4
0
 def test_remove_search(self) -> None:
     """
     Tests removing searches
     """
     with Database(DB) as db:
         db.add_search('google.com', 'test_name')
         db.add_search('yahoo.com', 'second_test')
         db.add_search('yahoo1.com', 'second_test')
         db.remove_search('google.com')
         db.cursor.execute('SELECT * from searches')
         self.assertEqual(2, len(db.cursor.fetchall()))
Ejemplo n.º 5
0
 def test_add_search(self) -> None:
     """
     Tests adding search to database
     """
     with Database(DB) as db:
         db.add_search('google.com', 'test_name')
         with self.assertRaises(sqlite3.IntegrityError):
             db.add_search('google.com', 'test_name')
         db.cursor.execute('SELECT url, name FROM searches')
         url, name = db.cursor.fetchone()
     self.assertEqual('google.com', url)
     self.assertEqual('test_name', name)
Ejemplo n.º 6
0
 def setUp(self) -> None:
     with open('tests/cred.txt') as file:
         sender, pw, recipient = file.read().split('\n')
     with Database(DB) as db:
         db.create_database()
         db.set_credentials(sender, pw, recipient)
     with Run(DB) as run:
         for make in MAKES:
             run.city = 'denver'
             run.seller_type = 'both'
             run.vehicle_type = 'motorcycle'
             run.make_model = f'auto_make_model={make.replace(" ", "+")}'
             run.do_add_search()
Ejemplo n.º 7
0
 def test_update_time(self) -> None:
     """
     Tests time update incrementation
     """
     with Database(DB) as db:
         db.add_search(URL, 'test_name')
         db.cursor.execute('SELECT updated FROM searches WHERE url = ?',
                           (URL, ))
         time_1 = db.cursor.fetchone()[0]
         db.update_time(URL)
         db.cursor.execute('SELECT updated FROM searches WHERE url = ?',
                           (URL, ))
         time_2 = db.cursor.fetchone()[0]
         self.assertGreater(time_2, time_1)
Ejemplo n.º 8
0
 def test_update_hits(self) -> None:
     """
     Tests that updating hits works properly
     """
     with Database(DB) as db:
         db.add_search(URL, 'test_name')
         db.update_hits(URL, '123', '456', '789')
         db.cursor.execute('SELECT hits FROM searches WHERE url = ?',
                           (URL, ))
         self.assertEqual('123,456,789', db.cursor.fetchone()[0])
         db.update_hits(URL, '10', '11', '12')
         db.cursor.execute('SELECT hits FROM searches WHERE url = ?',
                           (URL, ))
         self.assertEqual('123,456,789,10,11,12', db.cursor.fetchone()[0])
Ejemplo n.º 9
0
 def test_get_urls_time_limited(self) -> None:
     """
     Database.get_urls() is time limited to only return URLs that have been not been updated
     in the last hour, this is testing that functionality
     :return:
     """
     with Database(DB) as db:
         db.add_search(URL, 'test_name')
         db.add_search('yahoo', 'name2')
         db.add_search('msn.com', 'name3')
         urls = db.get_urls()
         self.assertEqual([URL, 'yahoo', 'msn.com'], urls)
         db.update_time(URL)
         urls = db.get_urls()
         self.assertEqual(['yahoo', 'msn.com'], urls)
         db.update_time('msn.com')
         urls = db.get_urls()
         self.assertEqual(['yahoo'], urls)
         db.update_time('yahoo')
         urls = db.get_urls()
         self.assertEqual([], urls)
Ejemplo n.º 10
0
 def setUp(self) -> None:
     with Database(DB) as db:
         db.create_database()
Ejemplo n.º 11
0
 def __init__(self, database: str = Config.database):
     super(Run, self).__init__()
     self.seller_abbrev = None
     self.db_file = database
     self.database = Database(self.db_file)
     self.database.create_database()
Ejemplo n.º 12
0
class Run(CarShell):
    """
    Final child of shell class hierarchy, implements the methods used to
    build the search URL, as well as CRUD methods for managing searches
    """
    def __init__(self, database: str = Config.database):
        super(Run, self).__init__()
        self.seller_abbrev = None
        self.db_file = database
        self.database = Database(self.db_file)
        self.database.create_database()

    def create_seller_abbrev(self) -> None:
        """
        Checks that self.vehicle_type and self.seller_type have been defined.
        If they have, sets seller_abbrev to proper value.
        :return: None
        """
        if self.seller_type and self.vehicle_type:
            if self.vehicle_type == 'motorcycle':
                self.seller_abbrev = MOTO_SELLER[self.seller_type]
            elif self.vehicle_type == 'cars/trucks':
                self.seller_abbrev = CAR_SELLER[self.seller_type]

    @property
    def search_url(self) -> str or None:
        """
        Creates search url
        :return: search URL string or None
        """
        self.create_seller_abbrev()
        non_options = 'stdin', 'stdout', 'name', 'mode', 'encoding', 'cmdqueue', \
                      'completekey', 'city', 'vehicle_type', 'seller_type', \
                      'seller_abbrev', 'database', 'lastcmd', 'completion_matches'
        options = {
            key: value
            for key, value in self.__dict__.items()
            if key not in non_options and value
        }
        sel_options = []
        if self.city and self.seller_abbrev and self.make_model:
            base_url = f'{self.CITY_DICT[self.city]}{self.seller_abbrev}?format=rss&'
            for key, value in options.items():
                if key in BOOL_OPTIONS:
                    # In order for toggle functionality to work, its value has to
                    # remain a boolean up until it's added to the selected options list
                    sel_options.append(BOOL_OPTIONS[key])
                else:
                    # All other options are in the completed form
                    sel_options.append(value)
                return base_url + '&'.join(sel_options)
        else:
            msg = 'At a minimum, you must set the city, seller type,' \
                  ' vehicle type and a make_model.'
            print(msg)

    def do_credentials(self, *args) -> None:
        """
        Allows user to store credentials in the database.  Uses
        utilities.credential_verification to verify that supplied credentials
        actually work.
        :param args:
        :return:
        """
        recipient = input('Recipient address: ')
        sender = input('Sender: ')
        password = getpass.getpass('Sender\'s password: '******'Verification failure!  Incorrect username / password?')

    @staticmethod
    def help_credentials() -> None:
        """
        Displays help message for credentials command
        """
        initial_desc = 'Used to set credentials for sending email messages'
        usage = 'Input the credentials as directed', 'Be sure that they are correct'
        help_message(initial_desc, usage, long_desc=None)

    @property
    def credentials(self) -> bool:
        """
        Determines whether or not credentials have been set.  Returns True if they
        have, False otherwise.
        """
        try:
            username, password, recipient = self.database.credentials
            if username and password and recipient:
                return True
        except TypeError:
            return False

    def do_add_search(self, *args) -> None:
        """
        Adds search URL to database
        :return:
        """
        url = self.search_url
        if url:
            try:
                name = self.make_model.split('=')[1].replace('+', ' ')
                print(f'Added {name} search.')
                self.database.add_search(url, name=name)
                self.reset_search_options()
            except sqlite3.IntegrityError:
                print('Each search must be unique!')

    def do_run_search(self, *args) -> None:
        """
        Run search and send email notification
        :param args:
        :return: None
        """
        try:
            user, password, recipient = self.database.credentials
        except TypeError:
            print('Ensure that credentials have been set successfully first.')
            return
        if user and password and recipient:
            hits = run_search(self.db_file)
            if hits:
                print('New hits found!')
                Message(user, password, recipient, hits).send()
            else:
                print('No new search hits.')

    @staticmethod
    def help_run_search() -> None:
        """
        Displays help message for run_message
        """
        initial_desc = 'Used to run search for all URLs in database'
        usage = ' simply run `run_search`',
        help_message(initial_desc, usage, long_desc=None)

    @staticmethod
    def help_add_search() -> None:
        """
        Displays help message for add_search command
        """
        initial_desc = 'Used to add search URL to database'
        usage = 'type `add_search`',
        long_desc = 'Remember, each search must be unique!',
        help_message(initial_desc, usage, long_desc)

    def do_delete_search(self, *args) -> None:
        """
        Draws deletion menu
        """
        # Creates a dictionary with a number corresponding to each search
        url_name = {
            num: item
            for num, item in enumerate(self.database.get_url_name())
        }
        if url_name:
            for key, value in url_name.items():
                # value[0] is the url, value[1] is the name
                print(f'{key}: {value[1]}')
            choice = input('Search to delete: ')
            try:
                choice = int(choice)
                self.database.remove_search(url_name[choice][0])
            except ValueError:
                print('Invalid choice')
            except KeyError:
                print('Invalid choice')
        else:
            print('No active searches')

    @staticmethod
    def help_delete_search() -> None:
        """
        Displays help menu for deletion menu
        """
        initial_desc = 'Used to delete searches from database'
        usage = 'Usage: type `delete_search`', 'Follow the prompts to remove a ' \
                                               'particular search'
        long_desc = 'Type the number listed next to the name to remove a search from ' \
                    'the database',\
                    'This process cannot be undone, so be careful!'
        help_message(initial_desc, usage, long_desc)

    def reset_search_options(self) -> None:
        """
        Sets search values to None
        :return: None
        """
        non_options = 'stdin', 'stdout', 'name', 'mode', 'encoding', 'cmdqueue', \
                      'completekey', 'city', 'vehicle_type', 'seller_type', \
                      'seller_abbrev', 'database', 'lastcmd', 'completion_matches', \
                      'db_file'
        for key in self.__dict__:
            if key not in non_options:
                self.__dict__[key] = None
        # `both` is the default option for seller_type
        self.__dict__['seller_type'] = 'both'

    def do_print_searches(self, *args) -> None:
        """
        Prints out names of all searches in the database
        """
        searches = self.database.get_url_name()
        if searches:
            print('Current searches')
            print('*' * 40)
            for item in searches:
                print(item[1])
            print('*' * 40)
        else:
            print('No active searches.')

    @staticmethod
    def help_print_searches() -> None:
        """
        Prints out help menu for print_searches
        """
        initial = 'Used to print out the current searches'
        usage = 'Usage: type `print_searches`',
        help_message(initial, usage, long_desc=None)