Skip to content

Commit

Permalink
Merge pull request #363 from AppQuality/develop
Browse files Browse the repository at this point in the history
release-11-05-2024
  • Loading branch information
cannarocks authored Dec 5, 2024
2 parents 8b6adfe + 8aa9c8b commit 45fcae4
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 16 deletions.
3 changes: 3 additions & 0 deletions deployment/after-install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ services:
environment:
PORT: 80
API_ROOT: ${API_ROOT}
UNGUESS_API_ROOT: '${UNGUESS_API_ROOT}'
UNGUESS_API_USERNAME: '${UNGUESS_API_USERNAME}'
UNGUESS_API_PASSWORD: '${UNGUESS_API_PASSWORD}'
SENDGRID_KEY: '${SENDGRID_KEY}'
DEFAULT_SENDER_MAIL: '${DEFAULT_SENDER_MAIL}'
DEFAULT_SENDER_NAME: '${DEFAULT_SENDER_NAME}'
Expand Down
10 changes: 10 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ const config: {
private: string;
};
GOOGLE_API_KEY: string;
unguessApi?: {
basePath?: string;
username?: string;
password?: string;
};
} = {
port: process.env.PORT || "3000",
apiRoot: false,
Expand Down Expand Up @@ -59,6 +64,11 @@ const config: {
},
CROWD_URL: process.env.CROWD_URL || "https://tryber.me/",
GOOGLE_API_KEY: process.env.GOOGLE_API_KEY || "",
unguessApi: {
basePath: process.env.UNGUESS_API_ROOT || "",
username: process.env.UNGUESS_API_USERNAME || "",
password: process.env.UNGUESS_API_PASSWORD || "",
},
};

if (process.env.SSL_CHAIN && process.env.SSL_PRIVATE) {
Expand Down
88 changes: 88 additions & 0 deletions src/features/class/Unguess.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import config from "@src/config";

class Unguess {
private baseUrl: string;
private username: string;
private password: string;

constructor() {
const { basePath, username, password } = config.unguessApi || {};
this.baseUrl = basePath || "";
this.username = username || "";
this.password = password || "";
}

/**
* Private method to fetch a token for API requests
*/
private async getToken(): Promise<string> {
const response = await fetch(`${this.baseUrl}/authenticate`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username: this.username,
password: this.password,
}),
});

if (!response.ok) {
throw new Error("Failed to authenticate: " + response.statusText);
}

const data = await response.json();
if (!data.token) {
throw new Error("Authentication failed: Token not found");
}

return data.token;
}

/**
* Private method to perform authenticated POST requests
*/
private async authPost(
path: string,
body: Record<string, any>
): Promise<any> {
const token = await this.getToken();
const response = await fetch(`${this.baseUrl}${path}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify(body),
});

if (!response.ok) {
throw new Error(`Failed to post to ${path}: ${response.statusText}`);
}

return response.json();
}

/**
* Public method to post a new customer
*/
public async postCustomer({
userId,
name,
}: {
userId: number;
name: string;
}): Promise<{ id: number; name: string }> {
const body = {
company: name,
pm_id: userId,
};
const result = await this.authPost("/workspaces", body);
return {
id: result.id,
name: result.name,
};
}
}

export default Unguess;
37 changes: 36 additions & 1 deletion src/routes/customers/_post/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,40 @@ import { tryber } from "@src/features/database";
import request from "supertest";

describe("POST /customers", () => {
beforeEach(async () => {
jest
.spyOn(global, "fetch")
.mockImplementation(
async (url: RequestInfo | URL, options?: RequestInit) => {
if (typeof url === "string" && url.includes("authenticate")) {
return Promise.resolve({
ok: true,
json: async () => ({ token: "token" }),
} as Response);
} else if (typeof url === "string" && url.includes("workspaces")) {
const newCustomer = await tryber.tables.WpAppqCustomer.do()
.insert({
company: "New Customer",
pm_id: 1,
})
.returning("id");

return Promise.resolve({
ok: true,
json: async () => ({
id: newCustomer[0].id,
name: "New Customer",
}),
} as Response);
}
return Promise.reject(new Error("Invalid URL"));
}
);
});

afterEach(async () => {
await tryber.tables.WpAppqCustomer.do().delete();
jest.restoreAllMocks();
});

it("Should answer 403 if not logged in", () => {
Expand All @@ -13,20 +45,23 @@ describe("POST /customers", () => {
.send({ name: "New project" })
.expect(403);
});

it("Should answer 403 if logged in without permissions", async () => {
const response = await request(app)
.post("/customers")
.send({ name: "New project" })
.set("Authorization", "Bearer tester");
expect(response.status).toBe(403);
});

it("Should answer 201 if logged as user with full access on campaigns", async () => {
const response = await request(app)
.post("/customers")
.send({ name: "New project" })
.set("Authorization", 'Bearer tester olp {"appq_campaign":true}');
expect(response.status).toBe(201);
});

it("Should answer 403 if logged as user with access to some campaigns", async () => {
const response = await request(app)
.post("/customers")
Expand Down Expand Up @@ -54,7 +89,7 @@ describe("POST /customers", () => {

const customers = getResponse.body;
expect(customers).toHaveLength(1);
expect(customers[0].id).toBe(id);
expect(customers[0].name).toBe(name);
expect(customers[0].id).toBe(id);
});
});
31 changes: 16 additions & 15 deletions src/routes/customers/_post/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/** OPENAPI-CLASS : post-customers */

import OpenapiError from "@src/features/OpenapiError";
import { tryber } from "@src/features/database";
import UserRoute from "@src/features/routes/UserRoute";
import Unguess from "@src/features/class/Unguess";

class RouteItem extends UserRoute<{
response: StoplightOperations["post-customers"]["responses"]["200"]["content"]["application/json"];
Expand All @@ -18,6 +18,7 @@ class RouteItem extends UserRoute<{
this.setError(403, new OpenapiError("You are not authorized to do this"));
return false;
}

return true;
}

Expand All @@ -26,23 +27,23 @@ class RouteItem extends UserRoute<{
}

protected async prepare(): Promise<void> {
const customer = await this.createCustomer();
const customer = await this.postCustomerUnguessApi();

return this.setSuccess(201, customer);
}

private async createCustomer() {
const customer = await tryber.tables.WpAppqCustomer.do()
.insert({
company: this.getBody().name,
pm_id: 0,
})
.returning("id");
const id = customer[0].id ?? customer[0];

return {
id: id,
name: this.getBody().name,
};
private async postCustomerUnguessApi() {
const unguess = new Unguess();

try {
const customer = await unguess.postCustomer({
userId: this.getTesterId(),
name: this.getBody().name,
});
return customer;
} catch (error) {
console.error("Error creating customer:", error);
}
}
}

Expand Down

0 comments on commit 45fcae4

Please sign in to comment.