Skip to content

Commit

Permalink
feat(api): implement votes controller (#262)
Browse files Browse the repository at this point in the history
* implement votes controller

* style: resolve style guide violations

---------

Co-authored-by: oXtxNt9U <[email protected]>
  • Loading branch information
oXtxNt9U and oXtxNt9U authored Oct 4, 2023
1 parent 2b64fd7 commit 2aa67ba
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 2 deletions.
51 changes: 51 additions & 0 deletions packages/api-http/integration/routes/votes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { describe, Sandbox } from "../../../test-framework";
import { prepareSandbox, ApiContext } from "../../test/helpers/prepare-sandbox";
import { request } from "../../test/helpers/request";

import transactions from "../../test/fixtures/transactions.json";
import votes from "../../test/fixtures/votes.json";

describe<{
sandbox: Sandbox;
}>("Votes", ({ it, afterAll, assert, afterEach, beforeAll, beforeEach, nock }) => {
let apiContext: ApiContext;

// TODO:
let options = { transform: false };

beforeAll(async (context) => {
nock.enableNetConnect();
apiContext = await prepareSandbox(context);
});

afterAll((context) => {
nock.disableNetConnect();
apiContext.dispose();
});

beforeEach(async (context) => {
await apiContext.reset();
});

afterEach(async (context) => {
await apiContext.reset();
});

it("/votes", async () => {
await apiContext.transactionRepository.save(transactions);
await apiContext.transactionRepository.save(votes);

const { statusCode, data } = await request("/votes", options);
assert.equal(statusCode, 200);
assert.equal(data.data, votes);
});

it("/votes/{id}", async () => {
await apiContext.transactionRepository.save(votes);

const id = votes[votes.length - 1].id;
const { statusCode, data } = await request(`/votes/${id}`, options);
assert.equal(statusCode, 200);
assert.equal(data.data, votes[votes.length - 1]);
});
});
60 changes: 60 additions & 0 deletions packages/api-http/source/controllers/votes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Boom from "@hapi/boom";
import Hapi from "@hapi/hapi";
import {
Contracts as ApiDatabaseContracts,
Identifiers as ApiDatabaseIdentifiers,
Search,
} from "@mainsail/api-database";
import { inject, injectable } from "@mainsail/container";
import { Contracts } from "@mainsail/contracts";

import { TransactionResource } from "../resources";
import { Controller } from "./controller";

@injectable()
export class VotesController extends Controller {
@inject(ApiDatabaseIdentifiers.TransactionRepositoryFactory)
private readonly transactionRepositoryFactory!: ApiDatabaseContracts.ITransactionRepositoryFactory;

@inject(ApiDatabaseIdentifiers.WalletRepositoryFactory)
private readonly walletRepositoryFactory!: ApiDatabaseContracts.IWalletRepositoryFactory;

public async index(request: Hapi.Request, h: Hapi.ResponseToolkit) {
const criteria: Search.Criteria.TransactionCriteria = {
...request.query,
type: Contracts.Crypto.TransactionType.Vote,
typeGroup: Contracts.Crypto.TransactionTypeGroup.Core,
};

const pagination = this.getListingPage(request);
const sorting = this.getListingOrder(request);
const options = this.getListingOptions();

const walletRepository = this.walletRepositoryFactory();
const transactions = await this.transactionRepositoryFactory().findManyByCritera(
walletRepository,
criteria,
sorting,
pagination,
options,
);

return this.toPagination(transactions, TransactionResource, request.query.transform);
}

public async show(request: Hapi.Request, h: Hapi.ResponseToolkit) {
const transaction = await this.transactionRepositoryFactory()
.createQueryBuilder()
.select()
.where("id = :id", { id: request.params.id })
.andWhere("type = :type", { type: Contracts.Crypto.TransactionType.Vote })
.andWhere("type_group = :typeGroup", { typeGroup: Contracts.Crypto.TransactionTypeGroup.Core })
.getOne();

if (!transaction) {
return Boom.notFound("Vote not found");
}

return this.respondWithResource(transaction, TransactionResource, request.query.transform);
}
}
3 changes: 2 additions & 1 deletion packages/api-http/source/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import * as Blocks from "./routes/blocks";
import * as Node from "./routes/node";
import * as Transactions from "./routes/transactions";
import * as ValidatorRounds from "./routes/validator-rounds";
import * as Votes from "./routes/votes";
import * as Wallets from "./routes/wallets";

export = {
name: "Public API",
async register(server: Hapi.Server): Promise<void> {
const handlers = [Blocks, Transactions, Node, ValidatorRounds, Wallets];
const handlers = [Blocks, Transactions, Node, ValidatorRounds, Votes, Wallets];

for (const handler of handlers) {
handler.register(server);
Expand Down
49 changes: 49 additions & 0 deletions packages/api-http/source/routes/votes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import Hapi from "@hapi/hapi";
import Joi from "joi";

import { VotesController } from "../controllers/votes";
import { pagination, transactionIdSchema, transactionSortingSchema } from "../schemas";

export const register = (server: Hapi.Server): void => {
const controller = server.app.app.resolve(VotesController);
server.bind(controller);

server.route({
handler: (request: Hapi.Request) => controller.index(request),
method: "GET",
options: {
plugins: {
pagination: {
enabled: true,
},
},
validate: {
query: Joi.object({
...server.app.schemas.transactionCriteriaSchemas,
orderBy: server.app.schemas.transactionsOrderBy,
transform: Joi.bool().default(true),
})
.concat(transactionSortingSchema)
.concat(pagination),
},
},
path: "/votes",
});

server.route({
handler: (request: Hapi.Request) => controller.show(request),
method: "GET",
options: {
plugins: {},
validate: {
params: Joi.object({
id: transactionIdSchema,
}),
query: Joi.object({
transform: Joi.bool().default(true),
}),
},
},
path: "/votes/{id}",
});
};
2 changes: 1 addition & 1 deletion packages/api-http/source/schemas/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Joi from "joi";

import { createSortingSchema, transactionCriteriaSchemas, walletAddressSchema, walletPublicKeySchema } from ".";

export const transactionIdSchema = Joi.string().hex().length(64);
export const transactionIdSchema = Joi.string().hex().max(96);

export const transactionCriteriaSchemaObject = {
id: Joi.alternatives(
Expand Down
23 changes: 23 additions & 0 deletions packages/api-http/test/fixtures/votes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[
{
"id": "3b08e13ba7ce26d8ee6de200b6cfb7ca90c583115e547c1b2ba7472a104a49b6",
"version": 1,
"type": 3,
"typeGroup": 1,
"blockId": "f99740cb19bbf7c85d78664532ef867ed36481655ed08868df3ab9657aae46e4",
"blockHeight": "60",
"sequence": 0,
"timestamp": "1696396878929",
"nonce": "1",
"senderPublicKey": "ac9a09dd85af1203cb5054d3f258e469ff831bf0ff1ee2cd90d6a46e52d11bae",
"recipientId": null,
"vendorField": null,
"amount": "0",
"fee": "100000000",
"asset": {
"votes": ["4724580539e22dde52d257f3e39e6fa9911659ddcc31b8b2971b5ed20e10e873"],
"unvotes": []
},
"signature": "219488e7d81f6133df7d978787278fe39633064111e687557764f7e45af75f4905e0a54325e4ac3ffce39f9a9aeb75ca758420e88abe7531173edaebfc74cbb1"
}
]

0 comments on commit 2aa67ba

Please sign in to comment.