Skip to content

Commit

Permalink
Merge pull request #41 from NYPL-Simplified/account_controller
Browse files Browse the repository at this point in the history
Added account controller that provides username and barcode. (Fixes #30)
  • Loading branch information
leonardr committed Jan 20, 2016
2 parents 18a2bec + fbda355 commit 242a531
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 0 deletions.
6 changes: 6 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ def feed(languages, lane_name):
def lane_search(languages, lane_name):
return app.manager.opds_feeds.search(languages, lane_name)

@app.route('/me', methods=['GET'])
@requires_auth
@returns_problem_detail
def account():
return app.manager.accounts.account()

@app.route('/loans/', methods=['GET', 'HEAD'])
@requires_auth
@returns_problem_detail
Expand Down
12 changes: 12 additions & 0 deletions controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ def setup_controllers(self):
self.index_controller = IndexController(self)
self.opds_feeds = OPDSFeedController(self)
self.loans = LoanController(self)
self.accounts = AccountController(self)
self.urn_lookup = URNLookupController(self._db)
self.work_controller = WorkController(self)

Expand Down Expand Up @@ -505,6 +506,17 @@ def search(self, languages, lane_name):
)
return feed_response(opds_feed)

class AccountController(CirculationManagerController):

def account(self):
header = flask.request.authorization

patron_info = self.manager.auth.patron_info(header.username)
return json.dumps(dict(
username=patron_info.get('username', None),
barcode=patron_info.get('barcode'),
))

class LoanController(CirculationManagerController):

def sync(self):
Expand Down
3 changes: 3 additions & 0 deletions firstbook.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ def request(self, url):
def dump(self, barcode):
return {}

def patron_info(self, barcode):
return dict(barcode=barcode)

def pintest(self, barcode, pin):
url = self.root + "&accesscode=%s&pin=%s" % tuple(map(
urllib.quote, (barcode, pin)
Expand Down
8 changes: 8 additions & 0 deletions millenium_patron.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,14 @@ def update_patron(self, patron, identifier, dump=None):
expires, self.EXPIRATION_DATE_FORMAT).date()
patron.authorization_expires = expires

def patron_info(self, identifier):
"""Get patron information from the ILS."""
dump = self.dump(identifier)
return dict(
barcode = dump.get(self.BARCODE_FIELD),
username = dump.get(self.USERNAME_FIELD),
)

def authenticated_patron(self, db, identifier, password):
# If they fail basic validation, there is no authenticated patron.
if not self.server_side_validation(identifier, password):
Expand Down
9 changes: 9 additions & 0 deletions opds.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,15 @@ def annotate_feed(self, feed, lane):
if self.patron:
self.add_patron(feed)

# Add an account info link
account_url = self.url_for('account', _external=True)
account_link = dict(
rel="http://librarysimplified.org/terms/rel/account",
type='application/json',
href=account_url,
)
feed.add_link(**account_link)

# Add a 'search' link.
if isinstance(lane, Lane):
lane_name = lane.url_name
Expand Down
22 changes: 22 additions & 0 deletions tests/test_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,24 @@ def test_authenticated_patron_root_lane(self):
eq_("http://cdn/groups/", response.headers['location'])


class TestAccountController(ControllerTest):

def test_patron_info_no_username(self):
with self.app.test_request_context(
"/", headers=dict(Authorization=self.valid_auth)):
account_info = json.loads(self.manager.accounts.account())
eq_(None, account_info.get('username'))
eq_("200", account_info.get('barcode'))

def test_patron_info_with_username(self):
auth = 'Basic ' + base64.b64encode('0:2222')
with self.app.test_request_context(
"/", headers=dict(Authorization=auth)):
account_info = json.loads(self.manager.accounts.account())
eq_("alice", account_info.get('username'))
eq_("0", account_info.get('barcode'))


class TestLoanController(ControllerTest):
def setup(self):
super(TestLoanController, self).setup()
Expand Down Expand Up @@ -536,6 +554,10 @@ def test_active_loans(self):
assert "%s/%s/borrow" % (threem_pool.data_source.name, threem_pool.identifier.identifier) in borrow_link
eq_(0, len(threem_revoke_links))

links = feed['feed']['links']
account_links = [link for link in links if link['rel'] == 'http://librarysimplified.org/terms/rel/account']
eq_(1, len(account_links))
assert 'me' in account_links[0]['href']

class TestWorkController(ControllerTest):

Expand Down
4 changes: 4 additions & 0 deletions tests/test_firstbook.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,7 @@ def test_server_side_validation(self):

def test_dump(self):
eq_({}, self.api.dump("abcd"))

def test_patron_info(self):
eq_("1234", self.api.patron_info("1234").get('barcode'))

8 changes: 8 additions & 0 deletions tests/test_millenium_patron.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,11 @@ def test_authenticated_patron_success(self):
alice = self.api.authenticated_patron(self._db, "alice", "4444")
eq_("44444444444447", alice.authorization_identifier)
eq_("alice", alice.username)

def test_patron_info(self):
self.api.enqueue("dump.success.html")
patron_info = self.api.patron_info("alice")
eq_("44444444444447", patron_info.get('barcode'))
eq_("alice", patron_info.get('username'))


0 comments on commit 242a531

Please sign in to comment.