v1.0.0 #28

Merged
bizcochito merged 147 commits from develop into main 2024-01-14 19:49:34 +00:00
8 changed files with 84 additions and 29 deletions
Showing only changes of commit 87f4719fd1 - Show all commits

View File

@ -1,5 +1,4 @@
name: Unit Tests with docker compose name: Unit Tests with docker compose
run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀
on: [pull_request] on: [pull_request]
jobs: jobs:

View File

@ -8,33 +8,20 @@ WORKDIR /usr/src/app
# install dependencies into temp folder # install dependencies into temp folder
# this will cache them and speed up future builds # this will cache them and speed up future builds
FROM base AS install FROM base AS install
RUN mkdir -p /temp/dev
COPY package.json bun.lockb /temp/dev/
RUN cd /temp/dev && bun install
# install with --production (exclude devDependencies) # install with --production (exclude devDependencies)
RUN mkdir -p /temp/prod RUN mkdir -p /temp/prod
COPY package.json bun.lockb /temp/prod/ COPY package.json bun.lockb /temp/prod/
RUN cd /temp/prod && bun install --production RUN cd /temp/prod && bun install --production
# copy node_modules from temp folder # Copy production dependencies and source code into final image
# then copy all (non-ignored) project files into the image
FROM install AS prerelease
COPY --from=install /temp/dev/node_modules node_modules
COPY . .
# [optional] tests & build
# ENV NODE_ENV=production
# RUN bun test
# RUN bun run build
# copy production dependencies and source code into final image
FROM base AS release FROM base AS release
COPY --from=install /temp/prod/node_modules node_modules COPY --from=install /temp/prod/node_modules node_modules
COPY --from=prerelease /usr/src/app/index.ts . COPY --from=install /usr/src/app/src ./src
COPY --from=prerelease /usr/src/app/package.json . COPY --from=install /usr/src/app/package.json .
# run the app # run the app
USER bun USER bun
ENV NODE_ENV=production
EXPOSE 8080/tcp EXPOSE 8080/tcp
CMD ["bun", "run", "start"] CMD ["bun", "run", "start"]

View File

@ -1,5 +1,33 @@
# bot-api # bot-api
## Introduction
The function of the API is basically to access the images' metadata stored in the database.
## Usage
The API exposes some endpoints to interact with the database.
### GET `/images`
Allows to get a list of image documents.
#### Query params
- `limit`: an optional parameter, which accepts a non-negative integer that dictates the number of documents that the list will have. If its value is equal to `0`, or if this parameter is missing, the endpoint will return all the image documents in the database.
- `status`: an optional parameter, which accepts the values `consumed`, `available` and `unavailable`. It filters the documents that have only the `status` attribute equal to that indicated in the parameter's value. If the parameter is missing, no filter will be applied to the document.
#### Example
- `GET /images?limit=5&status=available`: will return 5 documents that have the `available` value in their `status` attribute.
### PUT `/images/<id>`
Modifies an existing image document. The request must provide a JSON-formatted body, with one or more valid document attributes. The existing document attributes will be replaced with the provided new ones.
#### Params
- `id`: the id of the document to be modified.
#### Example
- `PUT /images/61f7e48f0c651345677b7775` with body `{ "status": "consumed" }`: will modify the document referenced by the `id` param, changing their `status` value to `consumed`.
### POST `/images`
### POST `/login`
## Installation
To install dependencies: To install dependencies:
```bash ```bash

View File

@ -14,6 +14,7 @@ app.get("/", (_, res) => {
}); });
app.get("/images", imageController.getAllImages); app.get("/images", imageController.getAllImages);
app.get("/images/:id", imageController.getImageById);
app.post("/images", authControler.authorize, imageController.addImage); app.post("/images", authControler.authorize, imageController.addImage);
app.post("/login", authControler.login); app.post("/login", authControler.login);

View File

@ -3,6 +3,23 @@ import imageService from "../services/ImageService";
import mongoose, { mongo } from "mongoose"; import mongoose, { mongo } from "mongoose";
class ImageController { class ImageController {
async getImageById(req: Request, res: Response) {
try {
const image = await imageService.findById(req.params.id);
if (image) {
res.json({ image });
} else {
res.status(404).json({ error: "Image not found" });
}
} catch (error: any) {
if (error instanceof mongoose.Error.CastError) {
res.status(400).json({ error: "Invalid Id" });
} else {
res.status(500).json({ error: "Internal Server Error" });
}
}
}
async getAllImages(_: Request, res: Response): Promise<void> { async getAllImages(_: Request, res: Response): Promise<void> {
try { try {
const images = await imageService.findAll(); const images = await imageService.findAll();

View File

@ -3,6 +3,10 @@ import { startApp } from "./app";
await startApp(); await startApp();
// This try carch is to prevent hot reload from making the process die due to coliding entries
try { try {
// Not insert test data into production
if (process.env.NODE_ENV != "production"){
await populateDatabase(); await populateDatabase();
}
} catch {} } catch {}

View File

@ -1,6 +1,10 @@
import imageModel, { Image } from "../models/ImageModel"; import imageModel, { Image } from "../models/ImageModel";
class ImageService { class ImageService {
async findById(id: string) {
const image = await imageModel.findOne({ _id: id });
return image;
}
async findAll(): Promise<Image[]> { async findAll(): Promise<Image[]> {
const allImages = await imageModel.find(); const allImages = await imageModel.find();
return allImages; return allImages;

View File

@ -1,11 +1,4 @@
import { import { afterEach, beforeAll, describe, expect, it, mock } from "bun:test";
afterEach,
beforeAll,
describe,
expect,
it,
mock,
} from "bun:test";
import request, { Response } from "supertest"; import request, { Response } from "supertest";
import app, { startApp } from "../src/app"; import app, { startApp } from "../src/app";
import imageService from "../src/services/ImageService"; import imageService from "../src/services/ImageService";
@ -86,8 +79,7 @@ describe("GET /images works properly", async () => {
}, },
})); }));
const res = await request(app) const res = await request(app).get("/images");
.get("/images");
expect(res.status).toBe(500); expect(res.status).toBe(500);
}); });
@ -185,3 +177,26 @@ describe("POST /images works properly", () => {
expect(res.status).toBe(400); expect(res.status).toBe(400);
}); });
}); });
describe("/images/:id works properly", () => {
it("should return 200 for existing ids", async () => {
const list = await request(app).get("/images");
const id = list.body.images[0]._id;
const res = await request(app).get(`/images/${id}`);
expect(res.status).toBe(200);
});
it("should return 404 for non-existing ids", async () => {
const list = await request(app).get("/images");
const id = "000000000000000000000000"; // this was the least posible to exist ID
if (!(id in list.body.images)) {
const res = await request(app).get(`/images/${id}`);
expect(res.status).toBe(404);
}
});
it("should return 400 for malformed ids", async () => {
const res = await request(app).get("/images/98439384");
expect(res.status).toBe(400);
});
});