示例#1
0
def end_poll():
    """Ends the poll.
    Called by the 'End Poll' actions.
    Only the user that created the poll is allowed to end it.
    All other user will receive an ephemeral error message.
    """
    json = request.get_json()
    user_id = json['user_id']
    team_id = json['team_id']
    poll_id = json['context']['poll_id']
    request.user_id = user_id

    try:
        poll = Poll.load(poll_id)
    except InvalidPollError:
        return jsonify({
            'ephemeral_text':
            tr("This poll is not valid anymore.\n"
               "Sorry for the inconvenience.")
        })

    app.logger.info('Ending poll "%s"', poll_id)

    # only the creator and admins may end a poll
    can_end_poll = \
        user_id == poll.creator_id or \
        is_admin_user(user_id) or \
        is_team_admin(user_id=user_id, team_id=team_id)

    if can_end_poll:
        poll.end()
        return jsonify({'update': {'props': format_poll(poll)}})

    return jsonify(
        {'ephemeral_text': tr("You are not allowed to end this poll")})
def test_format_poll_running(mocker):
    mocker.patch('formatters.resolve_usernames', new=lambda user_ids: user_ids)

    poll = Poll.create(creator_id='user0',
                       message='# Spam? **:tada:**',
                       vote_options=['Sure', 'Maybe', 'No'],
                       secret=False)
    poll.vote('user0', 0)
    poll.vote('user1', 1)
    poll.vote('user2', 2)
    poll.vote('user3', 2)

    with app.app.test_request_context(base_url='http://localhost:5005'):
        poll_dict = frmts.format_poll(poll)

    assert 'response_type' in poll_dict
    assert 'attachments' in poll_dict

    assert poll_dict['response_type'] == 'in_channel'
    attachments = poll_dict['attachments']
    assert len(attachments) == 1
    assert 'text' in attachments[0]
    assert 'actions' in attachments[0]
    assert 'fields' in attachments[0]
    assert attachments[0]['text'] == poll.message
    assert len(attachments[0]['actions']) == 4

    fields = attachments[0]['fields']
    assert len(fields) == 1
    assert 'short' in fields[0]
    assert 'title' in fields[0]
    assert 'value' in fields[0]
    assert not fields[0]['short']
    assert not fields[0]['title']
    assert fields[0]['value'] == '*Number of voters: 4*'
示例#3
0
def test_format_poll_bars_absolute_url(mocker):
    mocker.patch('formatters.resolve_usernames', new=lambda user_ids: user_ids)

    img_url = 'http://example.org/images/red_bar.png'
    with force_settings(BAR_IMG_URL=img_url):
        poll = Poll.create(
            creator_id='user0',
            message='# Spam? **:tada:**',
            vote_options=['Sure', 'Maybe', 'No'],
            bars=True,
        )
        poll.vote('user0', 0)
        poll.vote('user1', 1)
        poll.vote('user2', 2)
        poll.vote('user3', 2)
        poll.end()

        with app.app.test_request_context(base_url='http://localhost:5005'):
            poll_dict = frmts.format_poll(poll)

        assert 'response_type' in poll_dict
        assert 'attachments' in poll_dict

        attachments = poll_dict['attachments']
        fields = attachments[0]['fields']

        for field in fields[1:]:
            assert img_url in field['value']
            assert 'localhost' not in field['value']
示例#4
0
def test_format_poll_finished_public_bars(mocker):
    mocker.patch('formatters.resolve_usernames', new=lambda user_ids: user_ids)

    poll = Poll.create(
        creator_id='user0',
        message='# Spam? **:tada:**',
        vote_options=['Sure', 'Maybe', 'No'],
        bars=True,
        public=True,
    )
    poll.vote('user0', 0)
    poll.vote('user1', 1)
    poll.vote('user2', 2)
    poll.vote('user3', 2)
    poll.end()

    with app.app.test_request_context(base_url='http://localhost:5005'):
        poll_dict = frmts.format_poll(poll)

    assert 'response_type' in poll_dict
    assert 'attachments' in poll_dict

    assert poll_dict['response_type'] == 'in_channel'
    attachments = poll_dict['attachments']
    assert len(attachments) == 1
    assert 'text' in attachments[0]
    assert 'actions' not in attachments[0]
    assert 'fields' in attachments[0]
    assert attachments[0]['text'] == poll.message

    fields = attachments[0]['fields']
    assert len(fields) == 4

    assert 'short' in fields[0]
    assert 'title' in fields[0]
    assert 'value' in fields[0]
    assert not fields[0]['short']
    assert not fields[0]['title']
    assert fields[0]['value'] == '*Number of voters: 4*'

    img_url = 'http://localhost:5005/img/bar.png'
    expected = [
        (poll.vote_options[0], '1 Vote (25.0%)', 0.25, ['user0']),
        (poll.vote_options[1], '1 Vote (25.0%)', 0.25, ['user1']),
        (poll.vote_options[2], '2 Votes (50.0%)', 0.5, ['user2', 'user3']),
    ]
    for field, (title, value, bar_length, users) in zip(fields[1:], expected):
        assert 'short' in field
        assert 'title' in field
        assert 'value' in field
        assert not field['short']
        assert title == field['title']
        assert value in field['value']
        image = '![Bar]({} ={}x25)'.format(img_url, bar_length * 450 + 2)
        assert image in field['value']
        for user in users:
            assert user in field['value']
def test_format_poll_finished(mocker):
    mocker.patch('formatters.resolve_usernames', new=lambda user_ids: user_ids)

    poll = Poll.create(creator_id='user0',
                       message='# Spam? **:tada:**',
                       vote_options=['Sure', 'Maybe', 'No'],
                       secret=False)
    poll.vote('user0', 0)
    poll.vote('user1', 1)
    poll.vote('user2', 2)
    poll.vote('user3', 2)
    poll.end()

    with app.app.test_request_context(base_url='http://localhost:5005'):
        poll_dict = frmts.format_poll(poll)

    assert 'response_type' in poll_dict
    assert 'attachments' in poll_dict

    assert poll_dict['response_type'] == 'in_channel'
    attachments = poll_dict['attachments']
    assert len(attachments) == 1
    assert 'text' in attachments[0]
    assert 'actions' not in attachments[0]
    assert 'fields' in attachments[0]
    assert attachments[0]['text'] == poll.message

    fields = attachments[0]['fields']
    assert len(fields) == 4

    assert 'short' in fields[0]
    assert 'title' in fields[0]
    assert 'value' in fields[0]
    assert not fields[0]['short']
    assert not fields[0]['title']
    assert fields[0]['value'] == '*Number of voters: 4*'

    users = ['user0', 'user1', 'user2', 'user3']
    expected = [
        (poll.vote_options[0], '1 Vote (25.0%)'),
        (poll.vote_options[1], '1 Vote (25.0%)'),
        (poll.vote_options[2], '2 Votes (50.0%)'),
    ]
    for field, (title, value) in zip(fields[1:], expected):
        assert 'short' in field
        assert 'title' in field
        assert 'value' in field
        assert field['short']
        assert title == field['title']
        assert value == field['value']
        for user in users:
            assert user not in field['value']
示例#6
0
def vote():
    """Places a vote for a user.
    Called through the URL in the corresponding action (see
    formatters.format_actions).
    The JSON `context` is expected to contain a valid poll_id and the
    vote_id to vote for.
    """
    json = request.get_json()
    user_id = json['user_id']
    poll_id = json['context']['poll_id']
    vote_id = json['context']['vote']
    request.user_id = user_id

    try:
        poll = Poll.load(poll_id)
    except InvalidPollError:
        return jsonify({
            'ephemeral_text':
            tr("This poll is not valid anymore.\n"
               "Sorry for the inconvenience.")
        })

    app.logger.info('Voting in poll "%s" for user "%s": %i', poll_id, user_id,
                    vote_id)
    try:
        poll.vote(user_id, vote_id)
    except NoMoreVotesError:
        return jsonify({
            'ephemeral_text':
            tr("You already used all your votes.\n"
               "Click on a vote to unselect it again.")
        })

    return jsonify({
        'update': {
            'props': format_poll(poll)
        },
        'ephemeral_text':
        tr("Your vote has been updated:\n{}").format(
            format_user_vote(poll, user_id))
    })
示例#7
0
def poll():
    """Creates a new poll.
    Directly called by Mattermost.
    Example response data:
    ```
    {
        "response_type": "in_channel",
        "attachments": [{
            "text": "<Poll message>",
            "actions": [
            {
                "name": "<First Option> (0)",
                "integration": {
                    "context": {
                        "poll_id": "<unique_id>",
                        "vote": 0
                    },
                    "url": "http://<hostname:port>/vote"
                }
            },
            ... additional entries for all poll options ...
            {
                "name": "End Poll",
                "integration": {
                    "url": "http://<hostname:port>/end",
                    "context": {
                        "poll_id": "<unique_id>"
                    }
                }
            }],
            "fields": [
            {
                "short": false,
                "title": "",
                "value": "Number of Votes: 1"
            }]
        }]
    }
    ```
    """
    if hasattr(settings, 'MATTERMOST_TOKEN'):
        warnings.warn("MATTERMOST_TOKEN is deprecated, use MATTERMOST_TOKENS \
                      instead",
                      category=DeprecationWarning)
        settings.MATTERMOST_TOKENS = [settings.MATTERMOST_TOKEN]
        settings.MATTERMOST_TOKEN = None

    if settings.MATTERMOST_TOKENS:
        token = request.form['token']
        if token not in settings.MATTERMOST_TOKENS:
            return jsonify({
                'response_type':
                'ephemeral',
                'text':
                tr("The integration is not correctly set up: "
                   "Invalid token.")
            })

    if 'user_id' not in request.form:
        abort(400)
    if 'text' not in request.form:
        abort(400)
    user_id = request.form['user_id']
    request.user_id = user_id

    app.logger.debug('Received command: %s', request.form['text'])

    # the poll should have a fixed locale, otherwise it
    # changes for everyone every time someone votes
    locale = flask_babel.get_locale().language

    if request.form['text'].strip() == 'help':
        return jsonify({
            'response_type': 'ephemeral',
            'text': format_help(request.form['command'], locale)
        })

    args = parse_slash_command(request.form['text'])
    if not args.message:
        text = tr("**Please provide a message.**\n\n"
                  "**Usage:**\n{help}").format(
                      help=format_help(request.form['command'], locale))
        return jsonify({'response_type': 'ephemeral', 'text': text})
    if args.public:
        if not settings.MATTERMOST_URL or not settings.MATTERMOST_PA_TOKEN:
            return jsonify({
                'response_type':
                'ephemeral',
                'text':
                tr("Public polls are not available with the "
                   "current setup. Please check with you "
                   "system administrator.")
            })

    if args.locale:
        locale = args.locale

    poll = Poll.create(user_id,
                       message=args.message,
                       locale=locale,
                       vote_options=args.vote_options,
                       secret=not args.progress,
                       public=args.public,
                       max_votes=args.max_votes,
                       bars=args.bars)

    app.logger.info('Creating Poll: %s', poll.id)

    return jsonify(format_poll(poll))
示例#8
0
def poll():
    """Creates a new poll.
    Directly called by Mattermost.
    Example response data:
    ```
    {
        "response_type": "in_channel",
        "attachments": [{
            "text": "<Poll message>",
            "actions": [
            {
                "name": "<First Option> (0)",
                "integration": {
                    "context": {
                        "poll_id": "<unique_id>",
                        "vote": 0
                    },
                    "url": "http://<hostname:port>/vote"
                }
            },
            ... additional entries for all poll options ...
            {
                "name": "End Poll",
                "integration": {
                    "url": "http://<hostname:port>/end",
                    "context": {
                        "poll_id": "<unique_id>"
                    }
                }
            }],
            "fields": [
            {
                "short": false,
                "title": "",
                "value": "Number of Votes: 1"
            }]
        }]
    }
    ```
    """
    if hasattr(settings, 'MATTERMOST_TOKEN'):
        warnings.warn("MATTERMOST_TOKEN is deprecated, use MATTERMOST_TOKENS \
                      instead",
                      category=DeprecationWarning)
        settings.MATTERMOST_TOKENS = [settings.MATTERMOST_TOKEN]
        settings.MATTERMOST_TOKEN = None

    if settings.MATTERMOST_TOKENS:
        token = request.form['token']
        if token not in settings.MATTERMOST_TOKENS:
            return jsonify({
                'response_type':
                'ephemeral',
                'text':
                tr("The integration is not correctly set up: "
                   "Invalid token.")
            })

    if 'user_id' not in request.form:
        abort(400)
    if 'text' not in request.form:
        abort(400)
    user_id = request.form['user_id']
    request.user_id = user_id

    app.logger.debug('Received command: %s', request.form['text'])

    # the poll should have a fixed locale, otherwise it
    # changes for everyone every time someone votes
    locale = flask_babel.get_locale().language

    if request.form['text'].strip() == 'help':
        return jsonify({
            'response_type': 'ephemeral',
            'text': format_help(request.form['command'], locale)
        })

    args = parse_slash_command(request.form['text'])

    #debug
    #return jsonify({'response_type': 'ephemeral', 'text': str(args.progress)+str(args.lunch)+str(args.message)})

    # lunch
    # built new message and vote_options
    if args.lunch:
        lunch = Lunch()
        restaurants = lunch.read_restaurant()
        try:
            num_restaurant = int(args.message)
        except:
            num_restaurant = len(
                restaurants
            )  # if no number is provider as a message, just list all restautrant in the db
            #return jsonify({'ephemeral_text':tr("Please provide a number.")})
        restaurants_subset = random.sample(restaurants, num_restaurant)
        new_vote_options = restaurants_subset

        args_dict = args._asdict()
        args_dict['message'] = "Let's vote for lunch!"
        args_dict['vote_options'] = new_vote_options

        # copy from parse_slash_command
        Arguments = namedtuple('Arguments', [
            'message', 'vote_options', 'progress', 'public', 'max_votes',
            'bars', 'locale', 'lunch', 'lunchadd', 'lunchrm', 'lunchls'
        ])

        args = Arguments(**args_dict)

    if args.lunchadd:
        lunch = Lunch()
        flag = lunch.add_restaurant(author_id=user_id, restaurant=args.message)
        if flag:
            return jsonify({
                'response_type': 'ephemeral',
                'text': tr("Successfully added restaurant.")
            })
        else:
            return jsonify({
                'response_type': 'ephemeral',
                'text': tr("Error in adding restaurant.")
            })
    if args.lunchrm:
        lunch = Lunch()
        flag = lunch.rm_restaurant(args.message)
        if flag:
            return jsonify({
                'response_type': 'ephemeral',
                'text': tr("Successfully removed restaurant.")
            })
        else:
            return jsonify({
                'response_type': 'ephemeral',
                'text': tr("Error in removing restaurant.")
            })
    if args.lunchls:
        lunch = Lunch()
        restaurants = lunch.read_restaurant()
        restaurants_str = ",".join(restaurants)
        return jsonify({'response_type': 'ephemeral', 'text': restaurants_str})

    if not args.message:
        text = tr("**Please provide a message.**\n\n"
                  "**Usage:**\n{help}").format(
                      help=format_help(request.form['command'], locale))
        return jsonify({'response_type': 'ephemeral', 'text': text})
    if args.public:
        if not settings.MATTERMOST_URL or not settings.MATTERMOST_PA_TOKEN:
            return jsonify({
                'response_type':
                'ephemeral',
                'text':
                tr("Public polls are not available with the "
                   "current setup. Please check with you "
                   "system administrator.")
            })

    if args.locale:
        locale = args.locale

    poll = Poll.create(user_id,
                       message=args.message,
                       locale=locale,
                       vote_options=args.vote_options,
                       secret=not args.progress,
                       public=args.public,
                       max_votes=args.max_votes,
                       bars=args.bars)

    app.logger.info('Creating Poll: %s', poll.id)

    return jsonify(format_poll(poll))