Giter Site home page Giter Site logo

mealpy's People

Contributors

dbgrigsby avatar edmundmok avatar ipwnponies avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

mealpy's Issues

Credentials should not be requested at module level

mealpy/mealpy.py

Lines 110 to 114 in 2e35591

scheduler = BlockingScheduler()
print("Enter email: ")
email = input()
print("Enter password: ")
password = getpass.getpass()

The credentials are only needed for login (one place) and only the http session cookie is persisted afterwards. These variables are in global namespace and are going to linger around longer than wanted. Probably even possible to inspect and pull values from a long-live scheduled process. Edit: this is non-security concern, discussed a bit in #15. Basically, this is no worse than using keyring or reading password from OS env or file on disk.

Scheduler doesn't work

The scheduler was disabled during project boilerplate changes.

mealpy/mealpy.py

Lines 147 to 151 in 9e60e06

# scheduler.start()
if __name__ == '__main__':
execute_reserve_meal()

We'll want some way to allow user to run this adhoc or as scheduled task.

Add some tests

Let's add tests. More useful are the expected request response, having that schema or structure somewhere can make it easier to work on the code wihtout need to make a request every time. Mealpal responses also change based on time of day or week, when the "kitchen is closed", so this further unblocked development.

Limit reserving to during restaurant open hours

The schedules endpoint returns information for business hours. I think think this might be related to when the restaurant services mealpal orders:

The jsonpath is:

$.schedules[].restaurant.open
$.schedules[].restaurant.mpn_open

mealpy/tests/mealpy_test.py

Lines 223 to 226 in 3d10eb6

'open': '2019-04-01T00:00:00Z',
'close': '2019-04-01T00:00:00Z',
'mpn_open': '2019-04-01T00:00:00Z',
'mpn_close': '2019-04-01T00:00:00Z',

This can be useful to prevent user from reserving during closed times. Also can be added to list restaurants command output, so the user will have information to set up valid argument inputs.

Support meal preference priority

In IRL, if a meal is unavailable, the user decides on their second choice. Many users will probably have a common fallback. We should support this by accepting a ranked preference of meals/restaurants. The retry logic will need to understand when a meal is sold out (vs. a http timeout) and to attempt to reserve the next choice.

Suggestions for improvements

I tried this out and it's works pretty well. I want to improve this and want to know if you are accepting PR or if I fork this and go off on my own.

Things this project needs:

  • License (pick one, I suggest MIT for simplest use case). This allows me to modify and create PRs. Otherwise, I can only use my eyeballs to tell you things.

Ideas I am thinking of:

  • Setup instructions
  • Caching credentials/cookies, so you don't need to enter password every run
  • Caching restaurants for offline querying
  • Caching meal items
  • Ability to run this adhoc (not everyone needs scheduled runs, some just want to avoid using web interface)

Update README

Update README with instructions on how to use this script. This should wait until the code has stabilized first (probably sometime after 2019-04-05).

Use this template as a starting point.

Add cli arguments

The inputs to the script are hard-coded.

mealpy/mealpy.py

Lines 133 to 136 in 9e60e06

status_code = mp.reserve_meal(
'12:15pm-12:30pm',
restaurant_name='Coast Poke Counter - Battery St.',
city_name='San Francisco')

Add argparse to get these inputs.

Handle reservation failure

When attempting to reserve a meal that's booked out, the response is HTTP 400, with response:

{
  "error": "ERROR_AMOUNT_LIMIT"
}

It would be great handle this case, instead of retrying. Also will empower #9, since we can differentiate between when to retry and when to fallback to second choice.

mealpy/mealpy/mealpy.py

Lines 129 to 130 in 5fc5bc7

request = self.session.post(RESERVATION_URL, json=reserve_data)
return request.status_code

Config not found

FileNotFoundError when running script:

python mealpy/mealpy.py reserve foo bar sf
Traceback (most recent call last):
  File "mealpy/mealpy.py", line 229, in <module>
    cli()
...
Snipped for brevity
...
  File "mealpy/mealpy.py", line 138, in get_mealpal_credentials
    config = load_config()
  File "mealpy/mealpy.py", line 49, in load_config
    copyfile(template_config_path, config_path)
  File "/Users/ipwponies/repos/mealpy/venv/lib/python3.7/shutil.py", line 120, in copyfile
    with open(src, 'rb') as fsrc:
FileNotFoundError: [Errno 2] No such file or directory: '/Users/ipwnponies/repos/mealpy/mealpy/config.template.yaml'

This was introduced in PR #20, whenmealpal.py was moved to a package.

Build is broken

Build is broken. This was introduced when I added check-requirements for #13 .

The issue is that ipython installs conditional dependencies based on OS platform and requirements-tools doesn't handle this edge case. Options for fixing:

  • Move check-requirements from make test, maybe make it the responsibility of dev who updates requirements to run. It's only a sanity/safety check
  • Remove ipython from requirements-dev. That and pudb are optional tools that should be installed adhoc, per developer setup. Maybe restrict requirements-dev to only tooling necessary to deploy, i.e. pytest

Config customization doesn't work

We want the config feature to read a default config and then apply user customizations, similar to Hiera for Puppet. The config template is shipped with code and not intended to be modified, it serves as a template for users to copy and see all possible values. The the user's config is applied on top:

config.update(load_config_from_file(config_path, schema))

The bug is that this uses load_config_from_file, which does shema validation, and will fail due to missing values. What we probably want to do instead is naively update user's values and then rerun validation (or not, extra values should be ignored).

We could also have a minimal schema set for values the user must set. e.g. API tokens. But there's no use case for this yet, just dropping the thought for future reference.

Script fails if restaurant or meal doesn't exist

next() is used with no default, this will raise StopIteration if not matched:

mealpy/mealpy/mealpy.py

Lines 88 to 93 in a580ab5

def get_schedule_by_restaurant_name(self, restaurant_name, city_name):
restaurant = next(
i
for i in self.get_schedules(city_name)
if i['restaurant']['name'] == restaurant_name
)

The behaviour of early exit is fine (we can't fallback to another option if it's ambiguous). We probably want to default to None, do truthy check , then print a a friendlier message to the user or raise a more meaningful error. This will be useful in the future, to do something like email the user when their meal could not be booked.

Auth is only needed for some URLs

I discovered that no auth is required for getting city or menus. Likely only for POST calls, KITCHEN_URL and RESERVATION_URL.

I suggest we whitelist the URLs (operations) that require credential. This makes cli commands to list cities or menus (#7) simpler to test and run, since it's stateless and doesn't require requests session or unnecessary logins.

Setup travisci

We're starting to see more contributors and we have some tests. Let's set up TravisCI to automatically run tests on PRs, reduces the need to ask if they've ran unit tests, can instead focus on what manual verification was done.

@edmundmok, as the repository owner, can you enable TravisCI? From this stackoverflow post, I can do the rest of the setup via travis.yml file.

Cache credentials so they don't need to be input every run

Cache credentials so they don't need to be input every time.

This can either be the password (encrypted, not plaintext) or http session cookie. I'm not familiar with how cookies TTL work, although it might be enough if the cookie can persist for a few days.

Script does not get password from keyring

Fix main thus, otherwise it does not get the password from the keyring:
if name == 'main':
EMAIL = load_config()['email_address']

if USE_KEYRING:
    # If we're using keyring, we should always grab from keyring instead of holding on to potentially stale password
    PASSWORD = keyring.get_password(KEYRING_SERVICENAME, EMAIL)
    if not PASSWORD:
        PASSWORD = getpass.getpass('Credential not yet stored in keychain, please enter password: ')
        keyring.set_password(
            KEYRING_SERVICENAME,
            EMAIL,
            PASSWORD)
else:
    PASSWORD = getpass.getpass('Enter password: ')

List restaurants, meals, and hours from cli

We can cache the response of the restaurant/meal/hours queries. This will provide users ability to lookup possible inputs to provide as arguments.

Meals might be trickier, since they can change day-to-day. That can be a follow-up to this ticket, the benefit of getting reasonable inputs to provide to CLI arguments is great enough on its own.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.