Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
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())
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
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),
    })
Ejemplo n.º 7
0
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),
        })
Ejemplo n.º 8
0
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)
Ejemplo n.º 9
0
    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,
        }
Ejemplo n.º 10
0
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,
    }
Ejemplo n.º 11
0
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)
Ejemplo n.º 12
0
 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))
Ejemplo n.º 13
0
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,
    }
Ejemplo n.º 14
0
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':}}
Ejemplo n.º 15
0
    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
Ejemplo n.º 16
0
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
Ejemplo n.º 17
0
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)
Ejemplo n.º 18
0
    # 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
Ejemplo n.º 19
0
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':}}
Ejemplo n.º 20
0
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':}}