Esempio n. 1
0
def sync_vote(request):
    trx_id = request.GET.get("trx_id")

    try:
        # block numbers must be integer
        block_num = int(request.GET.get("block_num"))
    except (TypeError, ValueError):
        return HttpResponse('Invalid block ID', status=400)

    c = LightsteemClient(nodes=["https://api.hive.blog"])
    block_data = c.get_block(block_num)
    if not block_data:
        # block data may return null if it's invalid
        return HttpResponse('Invalid block ID', status=400)

    vote_tx = None
    for transaction in block_data.get("transactions", []):
        if transaction.get("transaction_id") == trx_id:
            vote_tx = transaction
            break

    if not vote_tx:
        return HttpResponse('Invalid transaction ID', status=400)

    vote_op = None
    for op_type, op_value in transaction.get("operations", []):
        if op_type != "comment":
            continue
        vote_op = op_value

    if not vote_op:
        return HttpResponse("Couldn't find valid vote operation.", status=400)

    # validate json metadata
    if not vote_op.get("json_metadata"):
        return HttpResponse("json_metadata is missing.", status=400)

    json_metadata = json.loads(vote_op.get("json_metadata", ""))

    # json_metadata should indicate content type
    if json_metadata.get("content_type") != "poll_vote":
        return HttpResponse("content_type field is missing.", status=400)

    # check votes
    votes = json_metadata.get("votes", [])
    if not len(votes):
        return HttpResponse("votes field is missing.", status=400)

    # check the poll exists
    try:
        question = Question.objects.get(
            username=vote_op.get("parent_author"),
            permlink=vote_op.get("parent_permlink"),
        )
    except Question.DoesNotExist:
        return HttpResponse("parent_author/parent_permlink is not a poll.",
                            status=400)

    # Validate the choice
    choices = Choice.objects.filter(question=question, )
    selected_choices = []
    for choice in choices:
        for user_vote in votes:
            if choice.text == user_vote:
                selected_choices.append(choice)

    if not selected_choices:
        return HttpResponse("Invalid choices in votes field.", status=400)

    # check if the user exists in our database
    # if it doesn't, create it.
    try:
        user = User.objects.get(username=vote_op.get("author"))
    except User.DoesNotExist:
        user = User.objects.create_user(username=vote_op.get("author"))
        user.save()

    # check if we already registered a vote from that user
    if Choice.objects.filter(voted_users__username=vote_op.get("author"),
                             question=question).count() != 0:
        return HttpResponse("You have already voted on that poll.", status=400)

    # register the vote
    for selected_choice in selected_choices:
        selected_choice.voted_users.add(user)

    # add vote audit entry
    vote_audit = VoteAudit(question=question,
                           voter=user,
                           block_id=block_num,
                           trx_id=trx_id)
    vote_audit.save()

    return HttpResponse("Vote is registered to the database.", status=200)
Esempio n. 2
0
class TestClient(unittest.TestCase):
    NODES = ["https://api.steemit.com"]

    def setUp(self):
        self.client = Client(nodes=TestClient.NODES)

    def test_dynamic_api_selection(self):
        self.client('tags_api')
        self.assertEqual('tags_api', self.client.api_type)

    def test_default_api_selection(self):
        with requests_mock.mock() as m:
            m.post(TestClient.NODES[0], json={"result": {}})
            self.client.get_block(12323)
            self.assertEqual('condenser_api', self.client.api_type)

    def test_get_rpc_request_body_condenser_multiple_args(self):
        self.client('condenser_api')
        rpc_body = self.client.get_rpc_request_body(
            ('get_account_bandwidth', 'steemit', 'forum'), {
                'batch': True,
                'id': 1
            })

        self.assertEqual(
            "condenser_api.get_account_bandwidth",
            rpc_body["method"],
        )

        self.assertEqual(
            ('steemit', 'forum'),
            rpc_body["params"],
        )

    def test_get_rpc_request_body_condenser_single_arg(self):
        self.client('condenser_api')
        rpc_body = self.client.get_rpc_request_body(
            ('get_block', '123'),
            {},
        )

        self.assertEqual(
            ('123', ),
            rpc_body["params"],
        )

    def test_get_rpc_request_body_non_condenser_api_with_arg(self):
        self.client('database_api')
        rpc_body = self.client.get_rpc_request_body(
            ('list_vesting_delegations', {
                "start": [None],
                "limit": 20,
                "order": "by_delegation"
            }),
            {},
        )

        self.assertEqual(
            {
                'start': [None],
                'limit': 20,
                'order': 'by_delegation'
            }, rpc_body["params"])

    def test_get_rpc_request_body_non_condenser_api_no_arg(self):
        self.client('database_api')
        rpc_body = self.client.get_rpc_request_body(
            ('get_active_witnesses', ),
            {},
        )

        self.assertEqual({}, rpc_body["params"])

    def test_get_rpc_request_body_condenser_api_no_arg(self):
        rpc_body = self.client.get_rpc_request_body(
            ('get_active_witnesses', ),
            {},
        )

        self.assertEqual([], rpc_body["params"])

    def test_batch_rpc_calls(self):
        self.client.get_block(1, batch=True)
        self.client.get_block_header(2, batch=True)

        self.assertEqual(2, len(self.client.queue))
        self.assertEqual("condenser_api.get_block",
                         self.client.queue[0]["method"])
        self.assertEqual("condenser_api.get_block_header",
                         self.client.queue[1]["method"])

    def test_validate_response_rpc_error(self):
        resp = {
            'jsonrpc': '2.0',
            'error': {
                'code': -32000,
                'message': "Parse Error:Couldn't parse uint64_t",
                'data': ""
            },
            'id': 'f0acccf6-ebf6-4952-97da-89b248dfb0d0'
        }

        with self.assertRaises(lightsteem.exceptions.RPCNodeException):
            self.client.validate_response(resp)

    def test_validate_repsonse_batch_call(self):
        resp = [{
            'previous': '017d08b4416e4ea77d5f582ddf4fc06bcf888eef',
            'timestamp': '2018-08-11T10:25:00',
            'witness': 'thecryptodrive',
            'transaction_merkle_root': '23676c4bdc0074489392892bcf'
            '1a5b779f280c8e',
            'extensions': []
        }, {
            'previous': '017d08b55aa2520bc3a777eaec77e872bb6b8943',
            'timestamp': '2018-08-11T10:25:03',
            'witness': 'drakos',
            'transaction_merkle_root': 'a4be1913157a1be7e4ab'
            'c36a22ffde1c110e683c',
            'extensions': []
        }]
        validated_resp = self.client.validate_response(resp)

        self.assertEqual(True, isinstance(validated_resp, list))
        self.assertEqual(2, len(validated_resp))

    def test_validate_repsonse_batch_call_one_error_one_fail(self):
        resp = [{
            'previous': '017d08b4416e4ea77d5f582ddf4fc06bcf888eef',
            'timestamp': '2018-08-11T10:25:00',
            'witness': 'thecryptodrive',
            'transaction_merkle_root': '23676c4bdc0074489392892bcf'
            '1a5b779f280c8e',
            'extensions': []
        }, {
            'jsonrpc': '2.0',
            'error': {
                'code': -32000,
                'message': "Parse Error:Couldn't parse uint64_t",
                'data': ""
            },
            'id': 'f0acccf6-ebf6-4952-97da-89b248dfb0d0'
        }]

        with self.assertRaises(lightsteem.exceptions.RPCNodeException):
            self.client.validate_response(resp)

    def test_process_batch(self):
        with requests_mock.mock() as m:
            m.post(TestClient.NODES[0], json={"result": {}})
            self.client.get_block(12323, batch=True)
            self.client.get_block(1234, batch=True)

            self.assertEqual(2, len(self.client.queue))
            self.client.process_batch()
            self.assertEqual(0, len(self.client.queue))