def issue_priority_token(request, DBSession): priority_window = request.registry.settings.get('karakara.queue.add.limit.priority_window') # Aquire most recent priority token - if most recent token in past, set recent token to now try: latest_token = DBSession.query(PriorityToken).filter(PriorityToken.used==False).order_by(PriorityToken.valid_end.desc()).limit(1).one() latest_token_end = latest_token.valid_end except NoResultFound: latest_token_end = None if not latest_token_end or latest_token_end < now(): # When issueing the first priority token latest_token_end = now() + priority_window # get_queue_duration(request) # Adding entire queue here was unnessisary. # Do not issue tokens past the end of the event event_end = request.registry.settings.get('karakara.event.end') if event_end and latest_token_end > event_end: # Unable to issue token as event end log.debug('priority_token rejected - event end') return TOKEN_ISSUE_ERROR.EVENT_END priority_token_limit = request.registry.settings.get('karakara.queue.add.limit.priority_token') if priority_token_limit and latest_token_end > now()+priority_token_limit: # Unable to issue token as priority tokens are time limited log.debug('priority_token rejected - token limit') return TOKEN_ISSUE_ERROR.TOKEN_LIMIT # Do not issue another priority_token if current user alrady has a priority_token try: priority_token = DBSession.query(PriorityToken) \ .filter(PriorityToken.used==False) \ .filter(PriorityToken.session_owner==request.session['id']) \ .filter(PriorityToken.valid_end>now()) \ .one() if priority_token: log.debug('priority_token rejected - existing token') return TOKEN_ISSUE_ERROR.TOKEN_ISSUED except NoResultFound: pass # Issue the new token priority_token = PriorityToken() priority_token.session_owner = request.session['id'] priority_token.valid_start = latest_token_end priority_token.valid_end = latest_token_end + priority_window DBSession.add(priority_token) # TODO: replace with new one in lib #request.response.set_cookie('priority_token', json_cookie); # WebOb.set_cookie mangles the cookie with m.serialize() - so I rolled my own set_cookie priority_token_dict = priority_token.to_dict() priority_token_dict.update({ 'server_datetime': now(), # The client datetime and server datetime may be out. we need to return the server time so the client can calculate the difference }) json_cookie = json.dumps(priority_token_dict, default=json_object_handler) request.response.headerlist.append(('Set-Cookie', 'priority_token={0}; Path=/'.format(json_cookie))) log.debug('priority_token issued') return priority_token
def consume_priority_token(request, DBSession): try: token = DBSession.query(PriorityToken) \ .filter(PriorityToken.used==False) \ .filter(PriorityToken.session_owner==request.session['id']) \ .filter(PriorityToken.valid_start<=now(), PriorityToken.valid_end>now()) \ .one() token.used = True request.response.delete_cookie('priority_token') log.debug('priority_token consumed') return True except NoResultFound: return False
def consume_priority_token(request, DBSession): try: token = DBSession.query(PriorityToken) \ .filter(PriorityToken.used == False) \ .filter(PriorityToken.session_owner == request.session['id']) \ .filter(PriorityToken.valid_start <= now(), PriorityToken.valid_end > now()) \ .one() token.used = True request.response.delete_cookie('priority_token') log.debug('priority_token consumed') return True except NoResultFound: return False
def test_queue_limit(app, queue, queue_manager, tracks): """ Users should not be able to queue over xx minuets of tracks (settable in config) Users trying to add tracks after this time have a 'window period of priority' where they have first dibs. The user should be informed by the status flash message how long before they should retry there selection. """ # Ensure we don't have an existing priority token assert not get_cookie(app, 'priority_token') # Fill the Queue response = queue_manager.add_queue_item( track_id='t1', performer_name='bob1') # total_duration = 0sec response = queue_manager.add_queue_item( track_id='t1', performer_name='bob2') # 90sec (1min track + 30sec padding) response = queue_manager.add_queue_item( track_id='t1', performer_name='bob3' ) # 180sec (1min track + 30sec padding) - by adding this track we will be at 180sec, that is now OVER 150sec, the next addition will error # Fail quque add, get priority token response = queue_manager.add_queue_item(track_id='t1', performer_name='bob4', expect_errors=True) assert response.status_code == 400 cookie_priority_token = get_cookie(app, 'priority_token') assert cookie_priority_token.get('valid_start') assert cookie_priority_token.get('server_datetime') # Try queue add again and not get priority token give as we already have one response = queue_manager.add_queue_item(track_id='t1', performer_name='bob4', expect_errors=True) #assert 'already have' in response.json['messages'][0] assert 'view.queue_item.add.priority_token_already_issued' in response.text # Shift server time forward - simulate waiting 5 minuets - we should be in our priority token range now(now() + datetime.timedelta(minutes=5)) # Add the track using the power of the priority token response = queue_manager.add_queue_item(track_id='t1', performer_name='bob4') assert 'bob4' in [q['performer_name'] for q in queue_manager.items] assert not get_cookie( app, 'priority_token' ) # The priority token should be consumed and removed from the client # Tidyup after test now(datetime.datetime.now())
def test_queue_limit(app, tracks): """ Users should not be able to queue over xx minuets of tracks (settable in config) Users trying to add tracks after this time have a 'window period of priority' where they have first dibs. The user should be informed by the status flash message how long before they should retry there selection. """ assert get_queue(app) == [] response = app.put('/settings', { 'karakara.queue.add.limit' : '0:02:30 -> timedelta', # 150sec 'karakara.queue.track.padding' : '0:00:30 -> timedelta', 'karakara.queue.add.limit.priority_window': '0:05:00 -> timedelta', }) # Ensure we don't have an existing priority token assert not get_cookie(app, 'priority_token') # Fill the Queue response = app.post('/queue', dict(track_id='t1', performer_name='bob1')) # total_duration = 0sec response = app.post('/queue', dict(track_id='t1', performer_name='bob2')) # 90sec (1min track + 30sec padding) response = app.post('/queue', dict(track_id='t1', performer_name='bob3')) # 180sec (1min track + 30sec padding) - by adding this track we will be at 180sec, that is now OVER 150sec, the next addition will error # Fail quque add, get priority token response = app.post('/queue', dict(track_id='t1', performer_name='bob4'), expect_errors=True) assert response.status_code == 400 cookie_priority_token = get_cookie(app, 'priority_token') assert cookie_priority_token.get('valid_start') assert cookie_priority_token.get('server_datetime') # Try queue add again and not get priority token give as we already have one response = app.post('/queue.json', dict(track_id='t1', performer_name='bob4'), expect_errors=True) assert 'already have' in response.json['messages'][0] # Shift server time forward - simulate waiting 5 minuets - we should be in our priority token range now(now() + datetime.timedelta(minutes=5)) # Add the track using the power of the priority token response = app.post('/queue', dict(track_id='t1', performer_name='bob4')) assert 'bob4' in [q['performer_name'] for q in get_queue(app)] assert not get_cookie(app, 'priority_token') # The priority token should be consumed and removed from the client # Tidyup after test now(datetime.datetime.now()) response = app.put('/settings', { 'karakara.queue.add.limit': '0:00:00 -> timedelta' }) clear_queue(app)
def priority_tokens(request): priority_tokens = DBSession.query(PriorityToken)\ .filter(PriorityToken.valid_start >= now() - request.registry.settings.get('karakara.queue.add.duplicate.time_limit')) \ .order_by(PriorityToken.valid_start) return action_ok(data={ 'priority_tokens': (priority_token.to_dict('full') for priority_token in priority_tokens), })
def priority_tokens(request): # TODO: karakara.queue.add.duplicate.time_limit is the wrong value to use here priority_tokens = DBSession.query(PriorityToken)\ .filter(PriorityToken.valid_start >= now() - request.queue.settings.get('karakara.queue.add.duplicate.time_limit')) \ .order_by(PriorityToken.valid_start) return action_ok( data={ 'priority_tokens': tuple( priority_token.to_dict('full') for priority_token in priority_tokens), })
def test_event_end(app, tracks): assert get_queue(app) == [] response = app.put('/settings', { 'karakara.event.end': '{0} -> datetime'.format(now()+datetime.timedelta(minutes=0, seconds=30)), }) response = app.post('/queue', dict(track_id='t1', performer_name='bob')) response = app.post('/queue', dict(track_id='t1', performer_name='bob'), expect_errors=True) assert response.status_code == 400 assert 'ending soon' in response.text response = app.put('/settings', { 'karakara.event.end': ' -> datetime', }) clear_queue(app)
def _queue_item_for(self, queue_items_query): """ TODO: Get some unit tests around this functionality Ensure that the time_limit takes into account the current length of the queue as well Separate out the duplicate 'track' and 'performer' times rather than just 'duplicate.time_limit' Renamed 'duplicate.track_limit' to 'duplicate.limit.track.count' Consider better variable name for 'latest_queue_item' - it's the oldest know instance of that occurrence. """ time_limit = self.request.queue.settings.get('karakara.queue.add.duplicate.time_limit') track_limit = self.request.queue.settings.get('karakara.queue.add.duplicate.track_limit') performer_limit = self.request.queue.settings.get('karakara.queue.add.duplicate.performer_limit') queue_items = queue_items_query.all() played = [q for q in queue_items if q.status == 'played'] pending = [q for q in queue_items if q.status == 'pending'] track_count = len(played+pending) latest_queue_item = queue_items[0] if len(queue_items) else None track_status = QUEUE_DUPLICATE.NONE if track_limit and track_count >= track_limit: track_status = QUEUE_DUPLICATE.THRESHOLD elif pending: track_status = QUEUE_DUPLICATE.PENDING elif played: track_status = QUEUE_DUPLICATE.PLAYED performer_status = QUEUE_DUPLICATE.NONE if performer_limit and track_count >= performer_limit: performer_status = QUEUE_DUPLICATE.THRESHOLD estimated_next_add_time = datetime.timedelta(0) if time_limit and latest_queue_item: estimated_next_add_time = time_limit - (now() - latest_queue_item.time_touched) # time_touched is NOT an acceptable way of measuring this. We need to calculate the estimated track time, but that is really expensive return { 'queue_items': queue_items, 'played': played, 'pending': pending, 'track_status': track_status, 'track_limit': track_limit, 'performer_status': performer_status, 'performer_limit': performer_limit, 'estimated_next_add_time': estimated_next_add_time, 'track_count': track_count, }
def _queue_item_for(request, queue_items_query): time_limit = request.registry.settings.get( 'karakara.queue.add.duplicate.time_limit') track_limit = request.registry.settings.get( 'karakara.queue.add.duplicate.track_limit') performer_limit = request.registry.settings.get( 'karakara.queue.add.duplicate.performer_limit') queue_items = queue_items_query.all() played = [q for q in queue_items if q.status == 'played'] pending = [q for q in queue_items if q.status == 'pending'] track_count = len(played + pending) latest_queue_item = queue_items[0] if len(queue_items) else None track_status = QUEUE_DUPLICATE.NONE if track_limit and track_count >= track_limit: track_status = QUEUE_DUPLICATE.THRESHOLD elif pending: track_status = QUEUE_DUPLICATE.PENDING elif played: track_status = QUEUE_DUPLICATE.PLAYED performer_status = QUEUE_DUPLICATE.NONE if performer_limit and track_count >= performer_limit: performer_status = QUEUE_DUPLICATE.THRESHOLD estimated_next_add_time = datetime.timedelta(0) if time_limit and latest_queue_item: estimated_next_add_time = time_limit - ( now() - latest_queue_item.time_touched ) # time_touched is NOT an acceptable way of measuring this. We need to calculate the estimated track time, but that is really expensive return { 'queue_items': queue_items, 'played': played, 'pending': pending, 'track_status': track_status, 'track_limit': track_limit, 'performer_status': performer_status, 'performer_limit': performer_limit, 'estimated_next_add_time': estimated_next_add_time, 'track_count': track_count, }
def test_event_end(app, tracks): assert get_queue(app) == [] response = app.put( '/settings', { 'karakara.event.end': '{0} -> datetime'.format( now() + datetime.timedelta(minutes=0, seconds=30)), }) response = app.post('/queue', dict(track_id='t1', performer_name='bob')) response = app.post('/queue', dict(track_id='t1', performer_name='bob'), expect_errors=True) assert response.status_code == 400 assert 'ending soon' in response.text response = app.put('/settings', { 'karakara.event.end': ' -> datetime', }) clear_queue(app)
def log_event(request, **data): """ It is expected that python's logging framework is used to output these events to the correct destination. Logstash can then read/process this log output for overview/stats """ event = data.get('event') try: event = request.matched_route.name except Exception: pass try: event = request.context.__name__ except Exception: pass data.update({ 'event': event, 'session_id': request.session.get('id'), 'ip': request.environ.get('REMOTE_ADDR'), 'timestamp': now(), }) log_event_logger.info(json_string(data))
def _queue_item_for(request, queue_items_query): time_limit = request.registry.settings.get('karakara.queue.add.duplicate.time_limit') track_limit = request.registry.settings.get('karakara.queue.add.duplicate.track_limit') performer_limit = request.registry.settings.get('karakara.queue.add.duplicate.performer_limit') queue_items = queue_items_query.all() played = [q for q in queue_items if q.status == 'played'] pending = [q for q in queue_items if q.status == 'pending'] track_count = len(played+pending) latest_queue_item = queue_items[0] if len(queue_items) else None track_status = QUEUE_DUPLICATE.NONE if track_limit and track_count >= track_limit: track_status = QUEUE_DUPLICATE.THRESHOLD elif pending: track_status = QUEUE_DUPLICATE.PENDING elif played: track_status = QUEUE_DUPLICATE.PLAYED performer_status = QUEUE_DUPLICATE.NONE if performer_limit and track_count >= performer_limit: performer_status = QUEUE_DUPLICATE.THRESHOLD estimated_next_add_time = datetime.timedelta(0) if time_limit and latest_queue_item: estimated_next_add_time = time_limit - (now() - latest_queue_item.time_touched) # time_touched is NOT an acceptable way of measuring this. We need to calculate the estimated track time, but that is really expensive return { 'queue_items': queue_items, 'played': played, 'pending': pending, 'track_status': track_status, 'track_limit': track_limit, 'performer_status': performer_status, 'performer_limit': performer_limit, 'estimated_next_add_time': estimated_next_add_time, 'track_count': track_count, }
def queue_add(request): """ Add items to end of queue """ # Validation for field in ['track_id', 'performer_name']: if not request.params.get(field): raise action_error(message='no {0}'.format(field), code=400) track_id = request.params.get('track_id') try: track = DBSession.query(Track).get(track_id) assert track except AssertionError: raise action_error(message='track {0} does not exist'.format(track_id), code=400) # If not admin, check additional restrictions if not is_admin(request): # Duplucate performer resrictions performer_limit = request.registry.settings.get('karakara.queue.add.duplicate.performer_limit') if performer_limit: performer_name_count = _logic.queue_item_base_query(request, DBSession).filter(QueueItem.performer_name==request.params.get('performer_name')).count() if performer_name_count >= performer_limit: log.debug('duplicate performer restricted - {0}'.format(request.params.get('performer_name'))) raise action_error(message='unable to queue track. duplicate "performer_name" limit reached', code=400) # Duplicate Addition Restrictions track_queued = _logic.queue_item_for_track(request, DBSession, track.id) if track_queued['status']==_logic.QUEUE_DUPLICATE.THRESHOLD: log.debug('duplicate track restricted - {0}'.format(track.id)) raise action_error(message='unable to queue track. duplicate "track in queue" limit reached', code=400) # Max queue length restrictions queue_duration = _logic.get_queue_duration(request) # Event end time event_end = request.registry.settings.get('karakara.event.end') if event_end and now()+queue_duration > event_end: log.debug('event end restricted') raise action_error(message='Event will be ending soon and all the time has been alocated', code=400) # Queue time limit queue_limit = request.registry.settings.get('karakara.queue.add.limit') if queue_limit and queue_duration > queue_limit: # If no device priority token - issue token and abort # else consume the token and proceed with addition if not _logic.consume_priority_token(request, DBSession): # Issue a priority token priority_token = _logic.issue_priority_token(request, DBSession) if isinstance(priority_token, PriorityToken): raise action_error(message='Queue limit reached - You have been given a priority token and will have priority to queue a track in your priority timeslot', code=400) if priority_token==_logic.TOKEN_ISSUE_ERROR.EVENT_END: raise action_error(message='Event will be ending soon and all the time has been alocated', code=400) if priority_token==_logic.TOKEN_ISSUE_ERROR.TOKEN_ISSUED: raise action_error(message='You already have a priority token timeslot. Queue your track when your timeslot occurs', code=400) raise action_error(message='Queue limit reached - try queing a track later', code=400) queue_item = QueueItem() for key,value in request.params.items(): if hasattr(queue_item, key): setattr(queue_item, key, value) # Set session owner - if admin allow manual setting of session_owner via params if is_admin(request) and queue_item.session_owner: pass else: queue_item.session_owner = request.session['id'] DBSession.add(queue_item) log.info('add - %s to queue by %s' % (queue_item.track_id, queue_item.performer_name)) invalidate_queue(request) # Invalidate Cache invalidate_track(track_id) return action_ok(message='track queued', data={'queue_item.id':''}, code=201) #TODO: should return 201 and have id of newly created object. data={'track':{'id':}}
def issue(self): priority_window = self.settings.get( 'karakara.queue.add.limit.priority_window') # TODO: Depreciate this priority_window settings # This can be auto-calculated from the current average track length in the queue # Aquire most recent priority token - if most recent token in past, set recent token to now try: latest_token = DBSession.query(PriorityToken).filter( PriorityToken.used == False).order_by( PriorityToken.valid_end.desc()).limit(1).one() latest_token_end = latest_token.valid_end except NoResultFound: latest_token_end = None if not latest_token_end or latest_token_end < now(): # When issueing the first priority token latest_token_end = now( ) + priority_window # get_queue_duration(request) # Adding entire queue here was unnessisary. # Do not issue tokens past the end of the event event_end = self.settings.get('karakara.event.end') if event_end and latest_token_end > event_end: # Unable to issue token as event end log.debug('priority_token rejected - event end') return TOKEN_ISSUE_ERROR.EVENT_END # TODO: possibly depricate this - we can just keep staking tokens until the end of the event priority_token_limit = self.settings.get( 'karakara.queue.add.limit.priority_token') if priority_token_limit and latest_token_end > now( ) + priority_token_limit: # Unable to issue token as priority tokens are time limited log.debug('priority_token rejected - token limit') return TOKEN_ISSUE_ERROR.TOKEN_LIMIT # TODO: Look at the last priority tokens created and raise a warning if the token is likely to pass beyond the end of the event. # Do not issue another priority_token if current user already has a priority_token try: priority_token = DBSession.query(PriorityToken) \ .filter(PriorityToken.used==False) \ .filter(PriorityToken.session_owner==self.user_id) \ .filter(PriorityToken.valid_end>now()) \ .one() if priority_token: log.debug('priority_token rejected - existing token') return TOKEN_ISSUE_ERROR.TOKEN_ISSUED except NoResultFound: pass # Issue the new token priority_token = PriorityToken() priority_token.session_owner = self.user_id priority_token.valid_start = latest_token_end priority_token.valid_end = latest_token_end + priority_window DBSession.add(priority_token) # TODO: replace with new one in lib #request.response.set_cookie('priority_token', json_cookie); # WebOb.set_cookie mangles the cookie with m.serialize() - so I rolled my own set_cookie priority_token_dict = priority_token.to_dict() priority_token_dict.update({ 'server_datetime': now( ), # The client datetime and server datetime may be out. we need to return the server time so the client can calculate the difference }) json_cookie = json.dumps(priority_token_dict, default=json_object_handler) self.request.response.headerlist.append( ('Set-Cookie', 'priority_token={0}; Path=/'.format(json_cookie))) #self.request.response.set_cookie(name='priority_token', value=json_cookie, path='/', overwrite=True) # This method butchers the json and cannot be used log.debug('priority_token issued') return priority_token
def issue_priority_token(request, DBSession): priority_window = request.registry.settings.get( 'karakara.queue.add.limit.priority_window') # Aquire most recent priority token - if most recent token in past, set recent token to now try: latest_token = DBSession.query(PriorityToken).filter( PriorityToken.used == False).order_by( PriorityToken.valid_end.desc()).limit(1).one() latest_token_end = latest_token.valid_end except NoResultFound: latest_token_end = None if not latest_token_end or latest_token_end < now(): # When issueing the first priority token latest_token_end = now( ) + priority_window # get_queue_duration(request) # Adding entire queue here was unnessisary. # Do not issue tokens past the end of the event event_end = request.registry.settings.get('karakara.event.end') if event_end and latest_token_end > event_end: # Unable to issue token as event end log.debug('priority_token rejected - event end') return TOKEN_ISSUE_ERROR.EVENT_END priority_token_limit = request.registry.settings.get( 'karakara.queue.add.limit.priority_token') if priority_token_limit and latest_token_end > now() + priority_token_limit: # Unable to issue token as priority tokens are time limited log.debug('priority_token rejected - token limit') return TOKEN_ISSUE_ERROR.TOKEN_LIMIT # Do not issue another priority_token if current user alrady has a priority_token try: priority_token = DBSession.query(PriorityToken) \ .filter(PriorityToken.used==False) \ .filter(PriorityToken.session_owner==request.session['id']) \ .filter(PriorityToken.valid_end>now()) \ .one() if priority_token: log.debug('priority_token rejected - existing token') return TOKEN_ISSUE_ERROR.TOKEN_ISSUED except NoResultFound: pass # Issue the new token priority_token = PriorityToken() priority_token.session_owner = request.session['id'] priority_token.valid_start = latest_token_end priority_token.valid_end = latest_token_end + priority_window DBSession.add(priority_token) # TODO: replace with new one in lib #request.response.set_cookie('priority_token', json_cookie); # WebOb.set_cookie mangles the cookie with m.serialize() - so I rolled my own set_cookie priority_token_dict = priority_token.to_dict() priority_token_dict.update({ 'server_datetime': now( ), # The client datetime and server datetime may be out. we need to return the server time so the client can calculate the difference }) json_cookie = json.dumps(priority_token_dict, default=json_object_handler) request.response.headerlist.append( ('Set-Cookie', 'priority_token={0}; Path=/'.format(json_cookie))) log.debug('priority_token issued') return priority_token
def test_queue_limit(app, tracks): """ Users should not be able to queue over xx minuets of tracks (settable in config) Users trying to add tracks after this time have a 'window period of priority' where they have first dibs. The user should be informed by the status flash message how long before they should retry there selection. """ assert get_queue(app) == [] response = app.put( '/settings', { 'karakara.queue.add.limit': '0:02:30 -> timedelta', # 150sec 'karakara.queue.track.padding': '0:00:30 -> timedelta', 'karakara.queue.add.limit.priority_window': '0:05:00 -> timedelta', }) # Ensure we don't have an existing priority token assert not get_cookie(app, 'priority_token') # Fill the Queue response = app.post('/queue', dict(track_id='t1', performer_name='bob1')) # total_duration = 0sec response = app.post('/queue', dict( track_id='t1', performer_name='bob2')) # 90sec (1min track + 30sec padding) response = app.post( '/queue', dict(track_id='t1', performer_name='bob3') ) # 180sec (1min track + 30sec padding) - by adding this track we will be at 180sec, that is now OVER 150sec, the next addition will error # Fail quque add, get priority token response = app.post('/queue', dict(track_id='t1', performer_name='bob4'), expect_errors=True) assert response.status_code == 400 cookie_priority_token = get_cookie(app, 'priority_token') assert cookie_priority_token.get('valid_start') assert cookie_priority_token.get('server_datetime') # Try queue add again and not get priority token give as we already have one response = app.post('/queue.json', dict(track_id='t1', performer_name='bob4'), expect_errors=True) assert 'already have' in response.json['messages'][0] # Shift server time forward - simulate waiting 5 minuets - we should be in our priority token range now(now() + datetime.timedelta(minutes=5)) # Add the track using the power of the priority token response = app.post('/queue', dict(track_id='t1', performer_name='bob4')) assert 'bob4' in [q['performer_name'] for q in get_queue(app)] assert not get_cookie( app, 'priority_token' ) # The priority token should be consumed and removed from the client # Tidyup after test now(datetime.datetime.now()) response = app.put('/settings', {'karakara.queue.add.limit': '0:00:00 -> timedelta'}) clear_queue(app)
# Add the track using the power of the priority token response = queue_manager.add_queue_item(track_id='t1', performer_name='bob4') assert 'bob4' in [q['performer_name'] for q in queue_manager.items] assert not get_cookie( app, 'priority_token' ) # The priority token should be consumed and removed from the client # Tidyup after test now(datetime.datetime.now()) @with_settings(settings={ 'karakara.event.end': str(now() + datetime.timedelta(minutes=0, seconds=30)), }) def test_event_end(app, queue, queue_manager, tracks): response = queue_manager.add_queue_item(track_id='t1', performer_name='bob1') response = queue_manager.add_queue_item(track_id='t2', performer_name='bob2', expect_errors=True) assert response.status_code == 400 assert 'view.queue_item.add.event_end' in response.text def test_priority_tokens(app, queue): priority_token_url = f'/queue/{queue}/priority_tokens' response = app.get(priority_token_url, expect_errors=True) assert response.status_code == 403
def queue_item_add(request): """ Add items to end of queue """ _ = request.translate _log_event = partial(request.log_event, method='add') # Validation for field in ['track_id', 'performer_name']: if not request.params.get(field): raise action_error(message='no {0}'.format(field), code=400) track_id = request.params.get('track_id') try: track = DBSession.query(Track).get(track_id) assert track except AssertionError: raise action_error(message=_( 'view.queue_item.add.error.track_id ${track_id}', mapping={'track_id': track_id}), code=400) # If not admin, check additional restrictions if not is_admin(request): performer_name = request.params.get('performer_name').strip( ) # TODO: It would be good to ensure this value is writen to the db. However we cant modify the request.param dict directly. See creation of queueitem below # Valid performer name valid_performer_names = request.queue.settings.get( 'karakara.queue.add.valid_performer_names') if valid_performer_names and performer_name.lower() not in map( lambda name: name.lower(), valid_performer_names): message = _( 'view.queue_item.add.invalid_performer_name ${performer_name}', mapping=dict(performer_name=performer_name)) raise action_error(message, code=400) # TODO: Unify and tidy this shit .. Duplicate messages are very similat and can offload they db access to the model_logic. # Duplicate performer retractions queue_item_performed_tracks = request.queue.for_performer( performer_name) if queue_item_performed_tracks[ 'performer_status'] == QUEUE_DUPLICATE.THRESHOLD: try: latest_track_title = get_track( queue_item_performed_tracks['queue_items'] [0].track_id).title except Exception: latest_track_title = '' message = _( 'view.queue_item.add.dupicate_performer_limit ${performer_name} ${estimated_next_add_time} ${track_count} ${latest_queue_item_title}', mapping=dict(performer_name=performer_name, latest_queue_item_title=latest_track_title, **subdict(queue_item_performed_tracks, { 'estimated_next_add_time', 'track_count', }))) _log_event(status='reject', reason='dupicate.performer', message=message) raise action_error(message=message, code=400) # Duplicate Addition Restrictions queue_item_tracks_queued = request.queue.for_track(track.id) if queue_item_tracks_queued[ 'track_status'] == QUEUE_DUPLICATE.THRESHOLD: try: latest_track_title = get_track( queue_item_tracks_queued['queue_items'][0].track_id).title except Exception: latest_track_title = '' message = _( 'view.queue_item.add.dupicate_track_limit ${track_id} ${estimated_next_add_time} ${track_count} ${latest_queue_item_title}', mapping=dict(track_id=track.id, latest_queue_item_title=latest_track_title, **subdict(queue_item_tracks_queued, { 'estimated_next_add_time', 'track_count', }))) _log_event(status='reject', reason='duplicate.track', message=message) raise action_error(message=message, code=400) # Event end time event_end = request.queue.settings.get('karakara.event.end') if event_end and now() + request.queue.duration > event_end: log.debug('event end restricted') _log_event(status='reject', reason='event_end') raise action_error(message=_( 'view.queue_item.add.event_end ${event_end}', mapping={'event_end': event_end}), code=400) # Queue time limit queue_limit = request.queue.settings.get('karakara.queue.add.limit') if queue_limit and request.queue.duration > queue_limit: # If no device priority token - issue token and abort # else consume the token and proceed with addition priority_token_manager = PriorityTokenManager(request) if not priority_token_manager.consume(): # Issue a priority token priority_token = priority_token_manager.issue() if isinstance(priority_token, PriorityToken): _log_event(status='reject', reason='token.issued') raise action_error( message=_('view.queue_item.add.priority_token_issued'), code=400) if priority_token == TOKEN_ISSUE_ERROR.EVENT_END: _log_event(status='reject', reason='event_end') raise action_error(message=_( 'view.queue_item.add.event_end ${event_end}', mapping={'event_end': event_end}), code=400) if priority_token == TOKEN_ISSUE_ERROR.TOKEN_ISSUED: _log_event(status='reject', reason='token.already_issued') raise action_error(message=_( 'view.queue_item.add.priority_token_already_issued'), code=400) _log_event(status='reject', reason='token.limit') raise action_error( message=_('view.queue_item.add.token_limit'), code=400) queue_item = QueueItem() for key, value in request.params.items( ): # TODO: strip() the performer_name? if hasattr(queue_item, key): setattr(queue_item, key, value) queue_item.queue_id = request.context.queue_id # Set session owner - if admin allow manual setting of session_owner via params if is_admin(request) and queue_item.session_owner: pass else: queue_item.session_owner = request.session['id'] DBSession.add(queue_item) _log_event(status='ok', queue_id=queue_item.queue_id, track_id=queue_item.track_id, performer_name=queue_item.performer_name) #log.info('add - %s to queue by %s' % (queue_item.track_id, queue_item.performer_name)) message_data = { 'track_id': queue_item.track_id, 'performer_name': queue_item.performer_name } invalidate_cache(request, track_id) return action_ok( message=_('view.queue_item.add.ok ${track_id} ${performer_name}', mapping=message_data), data={'queue_item.id': ''}, code=201, ) # TODO: should return 201 and have id of newly created object. data={'track':{'id':}}
def queue_add(request): """ Add items to end of queue """ _ = request.translate _log_event = partial(log_event, request, method='add') # Validation for field in ['track_id', 'performer_name']: if not request.params.get(field): raise action_error(message='no {0}'.format(field), code=400) track_id = request.params.get('track_id') try: track = DBSession.query(Track).get(track_id) assert track except AssertionError: raise action_error(message=_('view.queue.add.error.track_id ${track_id}', mapping={'track_id': track_id}), code=400) # If not admin, check additional restrictions if not is_admin(request): performer_name = request.params.get('performer_name').strip() # TODO: It would be good to ensure this value is writen to the db. However we cant modify the request.param dict directly. See creation of queueitem below # Valid performer name valid_performer_names = request.registry.settings.get('karakara.queue.add.valid_performer_names') if valid_performer_names and performer_name.lower() not in map(lambda name: name.lower(), valid_performer_names): message = _('view.queue.add.invalid_performer_name ${performer_name}', mapping=dict( performer_name=performer_name )) raise action_error(message, code=400) # Duplucate performer resrictions queue_item_performed_tracks = _logic.queue_item_for_performer(request, DBSession, request.params.get('performer_name')) if queue_item_performed_tracks['performer_status'] == _logic.QUEUE_DUPLICATE.THRESHOLD: try: latest_track_title = get_track(queue_item_performed_tracks['queue_items'][0].track_id).title except Exception: latest_track_title = '' message = _('view.queue.add.dupicate_performer_limit ${performer_name} ${estimated_next_add_time} ${track_count} ${latest_queue_item_title}', mapping=dict( performer_name=performer_name, latest_queue_item_title=latest_track_title, **subdict(queue_item_performed_tracks, { 'estimated_next_add_time', 'track_count', }) )) _log_event(status='reject', reason='dupicate.performer', message=message) raise action_error(message=message, code=400) # Duplicate Addition Restrictions queue_item_tracks_queued = _logic.queue_item_for_track(request, DBSession, track.id) if queue_item_tracks_queued['track_status'] == _logic.QUEUE_DUPLICATE.THRESHOLD: message = _('view.queue.add.dupicate_track_limit ${track_id} ${estimated_next_add_time} ${track_count}', mapping=dict( track_id=track.id, **subdict(queue_item_performed_tracks, { 'estimated_next_add_time', 'track_count', }) )) _log_event(status='reject', reason='duplicate.track', message=message) raise action_error(message=message, code=400) # Max queue length restrictions queue_duration = _logic.get_queue_duration(request) # Event end time event_end = request.registry.settings.get('karakara.event.end') if event_end and now()+queue_duration > event_end: log.debug('event end restricted') _log_event(status='reject', reason='event_end') raise action_error(message=_('view.queue.add.event_end ${event_end}', mapping={'event_end': event_end}), code=400) # Queue time limit queue_limit = request.registry.settings.get('karakara.queue.add.limit') if queue_limit and queue_duration > queue_limit: # If no device priority token - issue token and abort # else consume the token and proceed with addition if not _logic.consume_priority_token(request, DBSession): # Issue a priority token priority_token = _logic.issue_priority_token(request, DBSession) if isinstance(priority_token, PriorityToken): _log_event(status='reject', reason='token.issued') raise action_error(message=_('view.queue.add.priority_token_issued'), code=400) if priority_token == _logic.TOKEN_ISSUE_ERROR.EVENT_END: _log_event(status='reject', reason='event_end') raise action_error(message=_('view.queue.add.event_end ${event_end}', mapping={'event_end': event_end}), code=400) if priority_token == _logic.TOKEN_ISSUE_ERROR.TOKEN_ISSUED: _log_event(status='reject', reason='token.already_issued') raise action_error(message=_('view.queue.add.priority_token_already_issued'), code=400) _log_event(status='reject', reason='token.limit') raise action_error(message=_('view.queue.add.token_limit'), code=400) queue_item = QueueItem() for key, value in request.params.items(): if hasattr(queue_item, key): setattr(queue_item, key, value) # Set session owner - if admin allow manual setting of session_owner via params if is_admin(request) and queue_item.session_owner: pass else: queue_item.session_owner = request.session['id'] DBSession.add(queue_item) _log_event(status='ok', track_id=queue_item.track_id, performer_name=queue_item.performer_name) #log.info('add - %s to queue by %s' % (queue_item.track_id, queue_item.performer_name)) invalidate_queue(request) # Invalidate Cache invalidate_track(track_id) return action_ok(message='track queued', data={'queue_item.id': ''}, code=201) # TODO: should return 201 and have id of newly created object. data={'track':{'id':}}