1

I'm attempting to use django to upload files to box.com using boxsdk, while deploying the app to heroku. The problem is that my code works fine on local dev server, but not on heroku. It also works if the app is run locally with heroku local web

For local dev server, I'm able to import a json file for auth. For heroku, since it wont accept conf files, I have used heroku:config to store the file as an environment variable.

from boxsdk import JWTAuth, Client
from io import StringIO
import os
jsonpath = f'{STATIC_ROOT}/conf/box.json'
try:
    auth = JWTAuth.from_settings_file(jsonpath)
except:
    BOXCONF = os.environ.get('BOXCONF')    
    msg = f'The value of BOXCONF is {BOXCONF}'
    capture_message(msg)
    auth = JWTAuth.from_settings_file(StringIO.new(BOXCONF))
client = Client(auth)
service_account = client.user().get()
print('Service Account user ID is {0}'.format(service_account.id))

I have tested that BOXCONF is set, by using capture_message of Sentry, and it displays the following:

The value of BOXCONF is {
"boxAppSettings": {
    "clientID": "abcd",
    "clientSecret": "abc",
    "appAuth": {
    "publicKeyID": "xyz",
    "privateKey": "-----BEGIN ENCRYPTED PRIVATE KEY-----\nblabla\n-----END ENCRYPTED PRIVATE KEY-----\n",
    "passphrase": "1234"
    }
},
"enterpriseID": "1234"
}

The error message I receive is:

AttributeError: 'NoneType' object has no attribute 'from_settings_file'
File "django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
File "django/core/handlers/base.py", line 126, in _get_response
    response = self.process_exception_by_middleware(e, request)
File "django/core/handlers/base.py", line 124, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "django/contrib/auth/decorators.py", line 21, in _wrapped_view
    return view_func(request, *args, **kwargs)
File "app/views.py", line 281, in fileupload
    link = handle_uploaded_file(request.FILES['docfile'], sectionchoice, sectiontext, sectiondescription, filename, filedescription)
File "app/views.py", line 353, in handle_uploaded_file
    auth = JWTAuth.from_settings_file(StringIO.new(BOXCONF))
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Joel G Mathew
  • 7,561
  • 15
  • 54
  • 86
  • That isn't your full code. Somewhere you're setting JWTAuth to None. Show the whole handle_uploaded_file function. (And I should note, that is a strange place to be doing authentication.) – Daniel Roseman Dec 26 '18 at 01:47
  • That is the full code in that function. At least upto the line causing error – Joel G Mathew Dec 26 '18 at 01:53
  • Are those imports really inside the function itself? Where is the function definition? – Daniel Roseman Dec 26 '18 at 02:05
  • The function is placed last in views.py. Yes, those imports were in the function definition. I've tried moving them to the beginning of views, with no change. – Joel G Mathew Dec 26 '18 at 08:57

1 Answers1

5

I confess that I overlooked a part of the documentation for boxsdk, which mentions that JWTAuth for boxsdk requires that boxsdk be installed with additional dependencies for JWTAuth.

So in my case, for the local machine, I needed to do:

pip install boxsdk[jwt]

And for heroku, I needed to add the following to requirements.txt:

boxsdk[jwt]>=2.0.0

Once boxsdk was installed with proper dependencies, the error disappeared. The clue was in how the required method was absent in a dir of the module. Thanks to Matt Willer of the Box dev team for pointing me in the right direction.

Joel G Mathew
  • 7,561
  • 15
  • 54
  • 86