def test_set_learning_context(db_conn, users_table): """ Expect to set the learning context. """ users_table.insert({"id": "abcd1234", "name": "Dalton", "email": "*****@*****.**", "password": "******"}).run( db_conn ) user = get_user({"id": "abcd1234"}, db_conn) set_learning_context(user, card={"entity_id": "A"}) assert get_learning_context(user) == {"card": {"entity_id": "A"}} set_learning_context( user, unit={"entity_id": "B", "name": "Banana", "body": "Banana"}, set={"entity_id": "C", "name": "Coconut"} ) assert get_learning_context(user) == { "card": {"entity_id": "A"}, "unit": {"entity_id": "B", "name": "Banana", "body": "Banana"}, "set": {"entity_id": "C", "name": "Coconut"}, } set_learning_context(user, set=None) assert get_learning_context(user) == { "card": {"entity_id": "A"}, "unit": {"entity_id": "B", "name": "Banana", "body": "Banana"}, } set_learning_context(user, card=None, unit=None) assert get_learning_context(user) == {}
def test_set_learning_context(db_conn, users_table): """ Expect to set the learning context. """ users_table.insert({ 'id': 'abcd1234', 'name': 'Dalton', 'email': '*****@*****.**', 'password': '******', }).run(db_conn) user = get_user({'id': 'abcd1234'}, db_conn) set_learning_context(user, card={'entity_id': 'A'}) assert get_learning_context(user) == {'card': {'entity_id': 'A'}} set_learning_context(user, unit={ 'entity_id': 'B', 'name': 'Banana', 'body': "Banana", }, set={ 'entity_id': 'C', 'name': 'Coconut', }) assert get_learning_context(user) == { 'card': { 'entity_id': 'A', }, 'unit': { 'entity_id': 'B', 'name': 'Banana', 'body': "Banana", }, 'set': { 'entity_id': 'C', 'name': 'Coconut', } } set_learning_context(user, set=None) assert get_learning_context(user) == { 'card': { 'entity_id': 'A', }, 'unit': { 'entity_id': 'B', 'name': 'Banana', 'body': "Banana", }, } set_learning_context(user, card=None, unit=None) assert get_learning_context(user) == {}
def next_route(request): """ Tell the learner where to go next. TODO-3 should we move all `next` data from individual endpoints to this one, and have the UI call this endpoint each time to get the next state? """ current_user = get_current_user(request) if not current_user: return abort(401) context = get_learning_context(current_user) # If 'next' action, return that, # else 'next' is GET Choose Set if context.get('next'): return 200, { 'next': context['next'] } return 200, { 'next': { 'method': 'GET', 'path': '/s/users/{user_id}/sets' .format(user_id=current_user['id']), } }
def test_set_learning_context(db_conn): create_test_users(db_conn) user = get_user_by_id(db_conn, {'id': user_a_uuid}) set_learning_context(user, unit={'entity_id': 'abcd1234'}) context = get_learning_context(user) assert context assert context['unit']
def next_route(request): """ Tell the learner where to go next. TODO-3 should we move all `next` data from individual endpoints to this one, and have the UI call this endpoint each time to get the next state? """ current_user = get_current_user(request) if not current_user: return abort(401) context = get_learning_context(current_user) # If 'next' action, return that, # else 'next' is GET Choose Subject if context.get('next'): return 200, {'next': context['next']} return 200, { 'next': { 'method': 'GET', 'path': '/s/users/{user_id}/subjects'.format( user_id=convert_uuid_to_slug(current_user['id'])), } }
def choose_unit_route(request, subject_id, unit_id): """ Updates the learner's information based on the unit they have chosen. NEXT STATE POST Chosen Unit -> GET Learn Card """ # TODO-3 simplify this method. should it be broken up or moved to model? db_conn = request['db_conn'] current_user = get_current_user(request) if not current_user: return abort(401, 'NcrRkqIlSW-BkcWLBkwORQ') unit = get_latest_accepted_unit(db_conn, unit_id) if not unit: return abort(404, 'PIti_qwAQ7WXwQwNZertxw') # If the unit isn't in the subject... context = get_learning_context(current_user) subject_ids = [ convert_uuid_to_slug(subject['entity_id']) for subject in list_subjects_by_unit_recursive(db_conn, unit_id) ] context_subject_id = context.get('subject', {}).get('entity_id') if context_subject_id not in subject_ids: return 400, { 'errors': [{ 'message': 'Unit not in subject.', 'ref': 'r32fH0eCRZCivJoh-hKwZQ', }] } # Or, the unit doesn't need to be learned... status = judge(db_conn, unit, current_user) if status == "done": return 400, { 'errors': [{ 'message': 'Unit not needed.', 'ref': 'YTU27E63Rfiy3Rqmqd6Bew', }] } # Choose a card for the learner to learn card = choose_card(db_conn, current_user, unit) if card: next_ = { 'method': 'GET', 'path': '/s/cards/{card_id}/learn'.format( card_id=convert_uuid_to_slug(card['entity_id'])), } else: next_ = {} set_learning_context(current_user, unit=unit, card=card if card else None, next=next_) return 200, {'next': next_}
def test_get_learning_context(db_conn, users_table): """ Expect to get the learning context. """ users_table.insert({ 'id': 'abcd1234', 'name': 'Dalton', 'email': '*****@*****.**', 'password': '******', }).run(db_conn) user = get_user({'id': 'abcd1234'}, db_conn) redis.set( 'learning_context_abcd1234', json.dumps({ 'card': { 'entity_id': 'A' }, 'unit': { 'entity_id': 'B' }, 'set': { 'entity_id': 'C' }, })) assert get_learning_context(user) == { 'card': { 'entity_id': 'A' }, 'unit': { 'entity_id': 'B' }, 'set': { 'entity_id': 'C' }, } redis.delete('learning_context_abcd1234') assert get_learning_context(user) == {}
def choose_unit_route(request, set_id, unit_id): """ Updates the learner's information based on the unit they have chosen. NEXT STATE POST Chosen Unit -> GET Learn Card """ # TODO-3 simplify this method. should it be broken up or moved to model? db_conn = request['db_conn'] current_user = get_current_user(request) if not current_user: return abort(401) unit = Unit.get_latest_accepted(db_conn, unit_id) if not unit: return abort(404) # If the unit isn't in the set... context = get_learning_context(current_user) set_ids = [set_['entity_id'] for set_ in Set.list_by_unit_id(db_conn, unit_id)] if context.get('set', {}).get('entity_id') not in set_ids: return abort(400) status = judge(db_conn, unit, current_user) # Or, the unit doesn't need to be learned... if status == "done": return abort(400) # Choose a card for the learner to learn card = choose_card(db_conn, current_user, unit) if card: next_ = { 'method': 'GET', 'path': '/s/cards/{card_id}/learn' .format(card_id=card['entity_id']), } else: next_ = {} set_learning_context( current_user, unit=unit.data, card=card.data if card else None, next=next_ ) return 200, {'next': next_}
def choose_unit_route(request, subject_id, unit_id): """ Updates the learner's information based on the unit they have chosen. NEXT STATE POST Chosen Unit -> GET Learn Card """ # TODO-3 simplify this method. should it be broken up or moved to model? db_conn = request['db_conn'] current_user = get_current_user(request) if not current_user: return abort(401) unit = Unit.get_latest_accepted(db_conn, unit_id) if not unit: return abort(404) # If the unit isn't in the subject... context = get_learning_context(current_user) subject_ids = [ subject['entity_id'] for subject in Subject.list_by_unit_id(db_conn, unit_id) ] if context.get('subject', {}).get('entity_id') not in subject_ids: return abort(400) status = judge(db_conn, unit, current_user) # Or, the unit doesn't need to be learned... if status == "done": return abort(400) # Choose a card for the learner to learn card = choose_card(db_conn, current_user, unit) if card: next_ = { 'method': 'GET', 'path': '/s/cards/{card_id}/learn'.format(card_id=card['entity_id']), } else: next_ = {} set_learning_context(current_user, unit=unit.data, card=card.data if card else None, next=next_) return 200, {'next': next_}
def test_get_learning_context(db_conn, users_table): """ Expect to get the learning context. """ users_table.insert({"id": "abcd1234", "name": "Dalton", "email": "*****@*****.**", "password": "******"}).run( db_conn ) user = get_user({"id": "abcd1234"}, db_conn) redis.set( "learning_context_abcd1234", json.dumps({"card": {"entity_id": "A"}, "unit": {"entity_id": "B"}, "set": {"entity_id": "C"}}), ) assert get_learning_context(user) == { "card": {"entity_id": "A"}, "unit": {"entity_id": "B"}, "set": {"entity_id": "C"}, } redis.delete("learning_context_abcd1234") assert get_learning_context(user) == {}
def get_set_units_route(request, set_id): """ Present a small number of units the learner can choose from. NEXT STATE GET Choose Unit -> POST Choose Unit """ db_conn = request['db_conn'] # TODO-3 simplify this method. should it be part of the models? current_user = get_current_user(request) if not current_user: return abort(401) context = get_learning_context(current_user) next_ = { 'method': 'POST', 'path': '/s/sets/{set_id}/units/{unit_id}'.format(set_id=context.get( 'set', {}).get('entity_id'), unit_id='{unit_id}'), } set_learning_context(current_user, next=next_) set_ = Set.get_latest_accepted(db_conn, set_id) # Pull a list of up to 5 units to choose from based on priority. buckets = traverse(db_conn, current_user, set_) units = buckets['learn'][:5] # TODO-3 Time estimates per unit for mastery. return 200, { 'next': next_, 'units': [unit.deliver() for unit in units], # For the menu, it must return the name and ID of the set 'set': set_.deliver(), 'current_unit_id': context.get('unit', {}).get('entity_id'), }
def learn_card_route(request, card_id): """ Render the card's data, ready for learning. NEXT STATE GET Learn Card -> POST Respond Card """ db_conn = request['db_conn'] current_user = get_current_user(request) if not current_user: return abort(401, 'WBv3UeikTLu5AAwG9A0QZg') card = get_latest_accepted_card(db_conn, card_id) if not card: return abort(404, 'UgQHXzx4SSaHgJzHpRaL9g') # Make sure the current unit id matches the card context = get_learning_context(current_user) context_unit_id = context.get('unit', {}).get('entity_id') if context_unit_id != convert_uuid_to_slug(card['unit_id']): return 400, { 'errors': [{ 'name': 'unit_id', 'message': 'card not in current unit.', 'ref': 'd6rhaoCuRdW0f9j8AlMXBQ', }], } next_ = { 'method': 'POST', 'path': '/s/cards/{card_id}/responses'.format( card_id=convert_uuid_to_slug(card['entity_id'])) } set_learning_context(current_user, card=card, next=next_) return 200, { 'card': deliver_card(card, access='learn'), 'subject': context.get('subject'), 'unit': context.get('unit'), 'next': next_, }
def get_set_units_route(request, set_id): """ Present a small number of units the learner can choose from. NEXT STATE GET Choose Unit -> POST Choose Unit """ db_conn = request['db_conn'] # TODO-3 simplify this method. should it be part of the models? current_user = get_current_user(request) if not current_user: return abort(401) context = get_learning_context(current_user) next_ = { 'method': 'POST', 'path': '/s/sets/{set_id}/units/{unit_id}' .format(set_id=context.get('set', {}).get('entity_id'), unit_id='{unit_id}'), } set_learning_context(current_user, next=next_) set_ = Set.get_latest_accepted(db_conn, set_id) # Pull a list of up to 5 units to choose from based on priority. buckets = traverse(db_conn, current_user, set_) units = buckets['learn'][:5] # TODO-3 Time estimates per unit for mastery. return 200, { 'next': next_, 'units': [unit.deliver() for unit in units], # For the menu, it must return the name and ID of the set 'set': set_.deliver(), 'current_unit_id': context.get('unit', {}).get('entity_id'), }
def get_subject_units_route(request, subject_id): """ Present a small number of units the learner can choose from. NEXT STATE GET Choose Unit -> POST Choose Unit """ db_conn = request['db_conn'] # TODO-3 simplify this method. should it be part of the models? current_user = get_current_user(request) if not current_user: return abort(401, 'p_wleq0FRQ2HEuHKOJIb7Q') context = get_learning_context(current_user) next_ = { 'method': 'POST', 'path': '/s/subjects/{subject_id}/units/{unit_id}'.format( subject_id=context.get('subject', {}).get('entity_id'), unit_id='{unit_id}'), } set_learning_context(current_user, next=next_) subject = get_latest_accepted_subject(db_conn, subject_id) if not subject: return abort(404, '68VOXmd6Shq2cwAAktkFtw') # Pull a list of up to 5 units to choose from based on priority. buckets = traverse(db_conn, current_user, subject) units = buckets['learn'][:5] # TODO-3 Time estimates per unit for mastery. return 200, { 'next': next_, 'units': [deliver_unit(unit) for unit in units], # For the menu, it must return the name and ID of the subject 'subject': deliver_subject(subject), 'current_unit_id': context.get('unit', {}).get('entity_id'), }
def learn_card_route(request, card_id): """ Render the card's data, ready for learning. NEXT STATE GET Learn Card -> POST Respond Card """ db_conn = request['db_conn'] current_user = get_current_user(request) if not current_user: return abort(401) card = get_card_by_kind(db_conn, card_id) if not card: return abort(404) # Make sure the current unit id matches the card context = get_learning_context(current_user) if context.get('unit', {}).get('entity_id') != card['unit_id']: return abort(400) next_ = { 'method': 'POST', 'path': '/s/cards/{card_id}/responses' .format(card_id=card['entity_id']) } set_learning_context(current_user, card=card.data, next=next_) return 200, { 'card': card.deliver(access='learn'), 'set': context.get('set'), 'unit': context.get('unit'), 'next': next_, }
def learn_card_route(request, card_id): """ Render the card's data, ready for learning. NEXT STATE GET Learn Card -> POST Respond Card """ db_conn = request['db_conn'] current_user = get_current_user(request) if not current_user: return abort(401) card = get_card_by_kind(db_conn, card_id) if not card: return abort(404) # Make sure the current unit id matches the card context = get_learning_context(current_user) if context.get('unit', {}).get('entity_id') != card['unit_id']: return abort(400) next_ = { 'method': 'POST', 'path': '/s/cards/{card_id}/responses'.format(card_id=card['entity_id']) } set_learning_context(current_user, card=card.data, next=next_) return 200, { 'card': card.deliver(access='learn'), 'set': context.get('set'), 'unit': context.get('unit'), 'next': next_, }
def respond_to_card_route(request, card_id): """ Record and process a learner's response to a card. NEXT STATE POST Respond Card -> GET Learn Card ...when not ready -> GET Choose Unit ...when ready, but still units -> GET View Subject Tree ...when ready and done """ # TODO-3 simplify this method. # perhaps smaller methods or move to model layer? db_conn = request['db_conn'] current_user = get_current_user(request) if not current_user: return abort(401, 'XDVEHHLRSZqQNJW4Zi_iqw') card = get_latest_accepted_card(db_conn, card_id) if not card: return abort(404, 'TQZ3SmAhS1qBd274C9DG0w') # Make sure the card is the current one context = get_learning_context(current_user) context_card_id = context.get('card', {}).get('entity_id') if context_card_id != convert_uuid_to_slug(card['entity_id']): return 400, { 'errors': [{ 'message': 'Not the current card.', 'ref': 'XfmF52NmQnK_bbaxx-p8dg', }] } result = seq_update(db_conn, current_user, card, request['params'].get('response')) errors, response, feedback = (result.get('errors'), result.get('response'), result.get('feedback')) if errors: return 400, { 'errors': errors, 'ref': 'HfuW7_B-TByy8yh4FwgdrA', } subject = context.get('subject') unit = context.get('unit') status = judge(db_conn, unit, current_user) # If we are done with this current unit... if status == "done": buckets = traverse(db_conn, current_user, subject) # If there are units to be diagnosed... if buckets.get('diagnose'): unit = buckets['diagnose'][0] next_card = choose_card(db_conn, current_user, unit) next_ = { 'method': 'GET', 'path': '/s/cards/{card_id}/learn'.format( card_id=convert_uuid_to_slug(next_card['entity_id'])), } set_learning_context(current_user, card=next_card.data, unit=unit, next=next_) # If there are units to be learned or reviewed... elif buckets.get('learn') or buckets.get('review'): next_ = { 'method': 'GET', 'path': '/s/subjects/{subject_id}/units'.format( subject_id=convert_uuid_to_slug(subject['entity_id'])), } set_learning_context(current_user, card=None, unit=None, next=next_) # If we are out of units... else: next_ = { 'method': 'GET', 'path': '/s/subjects/{subject_id}/tree'.format( subject_id=convert_uuid_to_slug(subject['entity_id'])), } set_learning_context(current_user, card=None, unit=None, next=next_) # If we are still reviewing, learning or diagnosing this unit... else: next_card = choose_card(db_conn, current_user, unit) if next_card: next_ = { 'method': 'GET', 'path': '/s/cards/{card_id}/learn'.format( card_id=convert_uuid_to_slug(next_card['entity_id'])), } set_learning_context(current_user, card=next_card, next=next_) else: next_ = {} set_learning_context(current_user, next=next_) return 200, { 'response': deliver_response(response), 'feedback': feedback, 'next': next_, }
def respond_to_card_route(request, card_id): """ Record and process a learner's response to a card. NEXT STATE POST Respond Card -> GET Learn Card ...when not ready -> GET Choose Unit ...when ready, but still units -> GET View Set Tree ...when ready and done """ # TODO-3 simplify this method. # perhaps smaller methods or move to model layer? db_conn = request['db_conn'] current_user = get_current_user(request) if not current_user: return abort(401) card = get_card_by_kind(db_conn, card_id) if not card: return abort(404) # Make sure the card is the current one context = get_learning_context(current_user) if context.get('card', {}).get('entity_id') != card['entity_id']: return abort(400) r = seq_update(db_conn, current_user, card, request['params'].get('response')) errors, response, feedback = (r.get('errors'), r.get('response'), r.get('feedback')) if errors: return 400, { 'errors': errors, 'ref': 'wtyOJPoy4bh76OIbYp8mS3LP', } set_ = Set(context.get('set')) unit = Unit(context.get('unit')) status = judge(db_conn, unit, current_user) # If we are done with this current unit... if status == "done": buckets = traverse(db_conn, current_user, set_) # If there are units to be diagnosed... if buckets['diagnose']: unit = buckets['diagnose'][0] next_card = choose_card(db_conn, current_user, unit) next_ = { 'method': 'GET', 'path': '/s/cards/{card_id}/learn' .format(card_id=next_card['entity_id']), } set_learning_context( current_user, card=next_card.data, unit=unit.data, next=next_) # If there are units to be learned or reviewed... elif buckets['learn'] or buckets['review']: next_ = { 'method': 'GET', 'path': '/s/sets/{set_id}/units' .format(set_id=set_['entity_id']), } set_learning_context(current_user, card=None, unit=None, next=next_) # If we are out of units... else: next_ = { 'method': 'GET', 'path': '/s/sets/{set_id}/tree' .format(set_id=set_['entity_id']), } set_learning_context(current_user, card=None, unit=None, next=next_) # If we are still reviewing, learning or diagnosing this unit... else: next_card = choose_card(db_conn, current_user, unit) if next_card: next_ = { 'method': 'GET', 'path': '/s/cards/{card_id}/learn' .format(card_id=next_card['entity_id']), } set_learning_context(current_user, card=next_card.data, next=next_) else: next_ = {} set_learning_context(current_user, next=next_) return 200, { 'response': response.deliver(), 'feedback': feedback, 'next': next_, }
def get_set_tree_route(request, set_id): """ Render the tree of units that exists within a set. Contexts: - Search set, preview units in set - Pre diagnosis - Learner view progress in set - Set complete NEXT STATE GET View Set Tree -> GET Choose Set ...when set is complete -> GET Choose Unit ...when in learn or review mode -> GET Learn Card ...when in diagnosis (Unit auto chosen) TODO-2 merge with get_set_units_route TODO-2 simplify this method """ db_conn = request['db_conn'] set_ = Set.get(db_conn, entity_id=set_id) if not set_: return abort(404) units = set_.list_units(db_conn) # For the menu, it must return the name and ID of the set output = { 'set': set_.deliver(), 'units': [u.deliver() for u in units], } current_user = get_current_user(request) if not current_user: return 200, output context = get_learning_context(current_user) if current_user else {} buckets = traverse(db_conn, current_user, set_) output['buckets'] = { 'diagnose': [u['entity_id'] for u in buckets['diagnose']], 'review': [u['entity_id'] for u in buckets['review']], 'learn': [u['entity_id'] for u in buckets['learn']], 'done': [u['entity_id'] for u in buckets['done']], } # If we are just previewing, don't update anything if set_id != context.get('set', {}).get('entity_id'): return 200, output # When in diagnosis, choose the unit and card automagically. if buckets['diagnose']: unit = buckets['diagnose'][0] card = choose_card(db_conn, current_user, unit) next_ = { 'method': 'GET', 'path': '/s/cards/{card_id}/learn'.format(card_id=card['entity_id']), } set_learning_context(current_user, next=next_, unit=unit.data, card=card.data) # When in learn or review mode, lead me to choose a unit. elif buckets['review'] or buckets['learn']: next_ = { 'method': 'GET', 'path': '/s/sets/{set_id}/units'.format(set_id=set_id), } set_learning_context(current_user, next=next_) # If the set is complete, lead the learner to choose another set. else: next_ = { 'method': 'GET', 'path': '/s/users/{user_id}/sets'.format(user_id=current_user['id']), } set_learning_context(current_user, next=next_, unit=None, set=None) output['next'] = next_ return 200, output
def respond_to_card_route(request, card_id): """ Record and process a learner's response to a card. NEXT STATE POST Respond Card -> GET Learn Card ...when not ready -> GET Choose Unit ...when ready, but still units -> GET View Set Tree ...when ready and done """ # TODO-3 simplify this method. # perhaps smaller methods or move to model layer? db_conn = request['db_conn'] current_user = get_current_user(request) if not current_user: return abort(401) card = get_card_by_kind(db_conn, card_id) if not card: return abort(404) # Make sure the card is the current one context = get_learning_context(current_user) if context.get('card', {}).get('entity_id') != card['entity_id']: return abort(400) r = seq_update(db_conn, current_user, card, request['params'].get('response')) errors, response, feedback = (r.get('errors'), r.get('response'), r.get('feedback')) if errors: return 400, { 'errors': errors, 'ref': 'wtyOJPoy4bh76OIbYp8mS3LP', } set_ = Set(context.get('set')) unit = Unit(context.get('unit')) status = judge(db_conn, unit, current_user) # If we are done with this current unit... if status == "done": buckets = traverse(db_conn, current_user, set_) # If there are units to be diagnosed... if buckets['diagnose']: unit = buckets['diagnose'][0] next_card = choose_card(db_conn, current_user, unit) next_ = { 'method': 'GET', 'path': '/s/cards/{card_id}/learn'.format( card_id=next_card['entity_id']), } set_learning_context(current_user, card=next_card.data, unit=unit.data, next=next_) # If there are units to be learned or reviewed... elif buckets['learn'] or buckets['review']: next_ = { 'method': 'GET', 'path': '/s/sets/{set_id}/units'.format(set_id=set_['entity_id']), } set_learning_context(current_user, card=None, unit=None, next=next_) # If we are out of units... else: next_ = { 'method': 'GET', 'path': '/s/sets/{set_id}/tree'.format(set_id=set_['entity_id']), } set_learning_context(current_user, card=None, unit=None, next=next_) # If we are still reviewing, learning or diagnosing this unit... else: next_card = choose_card(db_conn, current_user, unit) if next_card: next_ = { 'method': 'GET', 'path': '/s/cards/{card_id}/learn'.format( card_id=next_card['entity_id']), } set_learning_context(current_user, card=next_card.data, next=next_) else: next_ = {} set_learning_context(current_user, next=next_) return 200, { 'response': deliver_response(response), 'feedback': feedback, 'next': next_, }
def get_set_tree_route(request, set_id): """ Render the tree of units that exists within a set. Contexts: - Search set, preview units in set - Pre diagnosis - Learner view progress in set - Set complete NEXT STATE GET View Set Tree -> GET Choose Set ...when set is complete -> GET Choose Unit ...when in learn or review mode -> GET Learn Card ...when in diagnosis (Unit auto chosen) TODO-2 merge with get_set_units_route TODO-2 simplify this method """ db_conn = request['db_conn'] set_ = Set.get(db_conn, entity_id=set_id) if not set_: return abort(404) units = set_.list_units(db_conn) # For the menu, it must return the name and ID of the set output = { 'set': set_.deliver(), 'units': [u.deliver() for u in units], } current_user = get_current_user(request) if not current_user: return 200, output context = get_learning_context(current_user) if current_user else {} buckets = traverse(db_conn, current_user, set_) output['buckets'] = { 'diagnose': [u['entity_id'] for u in buckets['diagnose']], 'review': [u['entity_id'] for u in buckets['review']], 'learn': [u['entity_id'] for u in buckets['learn']], 'done': [u['entity_id'] for u in buckets['done']], } # If we are just previewing, don't update anything if set_id != context.get('set', {}).get('entity_id'): return 200, output # When in diagnosis, choose the unit and card automagically. if buckets['diagnose']: unit = buckets['diagnose'][0] card = choose_card(db_conn, current_user, unit) next_ = { 'method': 'GET', 'path': '/s/cards/{card_id}/learn' .format(card_id=card['entity_id']), } set_learning_context( current_user, next=next_, unit=unit.data, card=card.data) # When in learn or review mode, lead me to choose a unit. elif buckets['review'] or buckets['learn']: next_ = { 'method': 'GET', 'path': '/s/sets/{set_id}/units' .format(set_id=set_id), } set_learning_context(current_user, next=next_) # If the set is complete, lead the learner to choose another set. else: next_ = { 'method': 'GET', 'path': '/s/users/{user_id}/sets' .format(user_id=current_user['id']), } set_learning_context(current_user, next=next_, unit=None, set=None) output['next'] = next_ return 200, output