@raketa-cloud/admin 0.0.93 → 0.0.94

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/jest.config.js CHANGED
@@ -11,8 +11,8 @@ const config = {
11
11
  ],
12
12
  coverageThreshold: {
13
13
  global: {
14
- branches: 71,
15
- functions: 74,
14
+ branches: 72,
15
+ functions: 75,
16
16
  lines: 78,
17
17
  statements: 78,
18
18
  },
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@raketa-cloud/admin",
3
- "version": "0.0.93",
3
+ "version": "0.0.94",
4
4
  "main": "src/index.js",
5
5
  "scripts": {
6
6
  "dev": "npx tailwindcss -i ./src/styles/application.css -o ../../apps/admin/static/application.css --watch",
7
- "test": "jest --coverage --coverageReporters=text --coverageReporters=\"text-summary\""
7
+ "test": "jest --coverage --coverageReporters=html --coverageReporters=\"text-summary\""
8
8
  },
9
9
  "devDependencies": {
10
10
  "@babel/core": "7.24.7",
@@ -102,7 +102,7 @@ const destroy = async (ctx) => {
102
102
  const { errors } = await ctx.client.redirects.delete(id);
103
103
 
104
104
  if (errors) {
105
- throw `Failed to delete redirect #${id}. WTF?`;
105
+ throw `Failed to delete redirect #${id}.`;
106
106
  }
107
107
 
108
108
  return {
@@ -92,7 +92,7 @@ const destroy = async (ctx) => {
92
92
  const { errors } = await ctx.client.tags.delete(id, ctx.locale);
93
93
 
94
94
  if (errors) {
95
- throw `Failed to delete tag #${id}. WTF?`;
95
+ throw `Failed to delete tag #${id}.`;
96
96
  }
97
97
 
98
98
  return {
@@ -106,7 +106,7 @@ const destroy = async (ctx) => {
106
106
 
107
107
  return {
108
108
  headers: {
109
- "HX-redirect": `/${ctx.locale}/${ctx.resourceConfig.categoryTypePlural}`,
109
+ "HX-Redirect": `/${ctx.locale}/${ctx.resourceConfig.categoryTypePlural}`,
110
110
  },
111
111
  json: {},
112
112
  };
@@ -31,7 +31,7 @@ export default class HTMLBuilder {
31
31
  }, "");
32
32
 
33
33
  if (children || nonVoid)
34
- return `<${tag} ${htmlAttributes}>${children}</${tag}>`;
34
+ return `<${tag} ${htmlAttributes}>${children ? children : ""}</${tag}>`;
35
35
 
36
36
  return `<${tag} ${htmlAttributes} />`;
37
37
  }
@@ -5,13 +5,16 @@ import currentPath from "./currentPath.cjs";
5
5
  import AuthHelper from "./helpers/AuthHelper";
6
6
  // TODO: Maybe change the encryption mechanism?
7
7
  import simpleCipher from "./simpleCipher";
8
+ import getConfig from "../../../apps/admin/src/getConfig";
8
9
 
9
10
  // Generate a random signing secret on every server restart
10
- const SIGNING_SECRET = randomBytes(64).toString("hex");
11
+ // const SIGNING_SECRET = randomBytes(64).toString("hex");
11
12
  const DELIMITER = ",";
12
13
 
13
14
  function calculateHash(text) {
14
- return createHmac("sha256", SIGNING_SECRET).update(text).digest("hex");
15
+ return createHmac("sha256", getConfig().secrets.signing_secret)
16
+ .update(text)
17
+ .digest("hex");
15
18
  }
16
19
 
17
20
  function obfuscateToken(token) {
@@ -1,14 +1,8 @@
1
+ import getConfig from "../../../apps/admin/src/getConfig";
2
+
1
3
  const ALPHABET =
2
4
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789,.";
3
5
 
4
- function generateKey() {
5
- const shuffled = ALPHABET.split("")
6
- .sort(() => Math.random() - 0.5)
7
- .join("");
8
-
9
- return shuffled;
10
- }
11
-
12
6
  function generateEncryptionLookup(key) {
13
7
  const lookup = {};
14
8
 
@@ -29,22 +23,38 @@ function generateDecryptionLookup(key) {
29
23
  return lookup;
30
24
  }
31
25
 
26
+ // function generateKey() {
27
+ // const shuffled = ALPHABET.split("")
28
+ // .sort(() => Math.random() - 0.5)
29
+ // .join("");
30
+
31
+ // return shuffled;
32
+ // }
33
+
32
34
  // Scramble lookup maps on every server restart
33
- const CIPHER_KEY = generateKey();
34
- const ENCRYPT_LOOKUP = generateEncryptionLookup(CIPHER_KEY);
35
- const DECRYPT_LOOKUP = generateDecryptionLookup(CIPHER_KEY);
35
+ // const CIPHER_KEY = generateKey();
36
+ // const ENCRYPT_LOOKUP = generateEncryptionLookup(CIPHER_KEY);
37
+ // const DECRYPT_LOOKUP = generateDecryptionLookup(CIPHER_KEY);
36
38
 
37
39
  function encrypt(plaintext) {
40
+ const ecryptLookup = generateEncryptionLookup(
41
+ getConfig().secrets.crypto_secret
42
+ );
43
+
38
44
  return plaintext
39
45
  .split("")
40
- .map((char) => ENCRYPT_LOOKUP[char] || char)
46
+ .map((char) => ecryptLookup[char] || char)
41
47
  .join("");
42
48
  }
43
49
 
44
50
  function decrypt(ciphertext) {
51
+ const decryptLookup = generateDecryptionLookup(
52
+ getConfig().secrets.crypto_secret
53
+ );
54
+
45
55
  return ciphertext
46
56
  .split("")
47
- .map((char) => DECRYPT_LOOKUP[char] || char)
57
+ .map((char) => decryptLookup[char] || char)
48
58
  .join("");
49
59
  }
50
60
 
@@ -0,0 +1,33 @@
1
+ import Logger from "../Logger";
2
+
3
+ describe("Logger", () => {
4
+ describe("error", () => {
5
+ test("Logs an error to the console", () => {
6
+ const logSpy = jest.spyOn(global.console, "error");
7
+
8
+ Logger.error({ foo: "BAR" });
9
+
10
+ expect(logSpy).toHaveBeenCalledWith("[ERROR]", "{ foo: 'BAR' }");
11
+ });
12
+ });
13
+
14
+ describe("info", () => {
15
+ test("Logs info to the console", () => {
16
+ const logSpy = jest.spyOn(global.console, "info");
17
+
18
+ Logger.info({ foo: "BAR" });
19
+
20
+ expect(logSpy).toHaveBeenCalledWith("[INFO]", "{ foo: 'BAR' }");
21
+ });
22
+ });
23
+
24
+ describe("debug", () => {
25
+ test("Logs debug information to the console", () => {
26
+ const logSpy = jest.spyOn(global.console, "debug");
27
+
28
+ Logger.debug({ foo: "BAR" });
29
+
30
+ expect(logSpy).toHaveBeenCalledWith("[DEBUG]", "{ foo: 'BAR' }");
31
+ });
32
+ });
33
+ });
@@ -45,7 +45,7 @@ describe("Redirects", () => {
45
45
  }));
46
46
 
47
47
  await expect(() => RedirectsHandler.destroy(ctx)).rejects.toMatch(
48
- "Failed to delete redirect #1. WTF?"
48
+ "Failed to delete redirect #1."
49
49
  );
50
50
 
51
51
  expect(mockDelete).toHaveBeenCalledWith(1);
@@ -43,7 +43,7 @@ describe("Tags Handler", () => {
43
43
  }));
44
44
 
45
45
  expect(() => TagsHandler.destroy(ctx)).rejects.toMatch(
46
- "Failed to delete tag #1. WTF?"
46
+ "Failed to delete tag #1."
47
47
  );
48
48
 
49
49
  expect(mockedDelete).toHaveBeenCalledWith("1", "en");
@@ -1,34 +1,38 @@
1
- import RedirectsHandler from "../../../handlers/RedirectsHandler";
2
- import Redirects from "../../../cloud/Redirects";
1
+ import CategoriesHandler from "../../../handlers/categories";
2
+ import Categories from "../../../cloud/Categories";
3
3
 
4
4
  import Factory from "../../support/factory";
5
5
 
6
6
  function buildCtx() {
7
7
  return {
8
8
  client: {
9
- redirects: new Redirects(() => ({}), "token"),
9
+ categories: new Categories(() => ({}), "token"),
10
10
  },
11
11
  params: { id: 1 },
12
12
  locale: "en",
13
+ resourceConfig: {
14
+ categoryType: "cat",
15
+ categoryTypePlural: "cats",
16
+ },
13
17
  };
14
18
  }
15
19
 
16
- describe("Redirects", () => {
20
+ describe("Categories", () => {
17
21
  test("destroy successful", async () => {
18
22
  const redirect = Factory.build("redirect");
19
23
  const ctx = buildCtx();
20
24
 
21
25
  const mockDelete = jest
22
- .spyOn(ctx.client.redirects, "delete")
26
+ .spyOn(ctx.client.categories, "delete")
23
27
  .mockImplementation(() => ({ redirect: redirect, errors: null }));
24
28
 
25
- const result = await RedirectsHandler.destroy(ctx);
29
+ const result = await CategoriesHandler.destroy(ctx);
26
30
 
27
- expect(mockDelete).toHaveBeenCalledWith(1);
31
+ expect(mockDelete).toHaveBeenCalledWith(1, "en");
28
32
 
29
33
  expect(result).toEqual({
30
34
  headers: {
31
- "HX-Redirect": "/en/redirects",
35
+ "HX-Redirect": "/en/cats",
32
36
  },
33
37
  json: {},
34
38
  });
@@ -38,16 +42,16 @@ describe("Redirects", () => {
38
42
  const ctx = buildCtx();
39
43
 
40
44
  const mockDelete = jest
41
- .spyOn(ctx.client.redirects, "delete")
45
+ .spyOn(ctx.client.categories, "delete")
42
46
  .mockImplementation(() => ({
43
47
  redirect: null,
44
48
  errors: [{ key: "generalError", message: "Not found" }],
45
49
  }));
46
50
 
47
- await expect(() => RedirectsHandler.destroy(ctx)).rejects.toMatch(
48
- "Failed to delete redirect #1. WTF?"
51
+ await expect(() => CategoriesHandler.destroy(ctx)).rejects.toEqual(
52
+ "Failed to delete category #1."
49
53
  );
50
54
 
51
- expect(mockDelete).toHaveBeenCalledWith(1);
55
+ expect(mockDelete).toHaveBeenCalledWith(1, "en");
52
56
  });
53
57
  });
@@ -0,0 +1,44 @@
1
+ import HTMLBuilder from "../../helpers/HTMLBuilder";
2
+
3
+ describe("HTMLBuilder", () => {
4
+ function normalizeHTML(html) {
5
+ return html.replace(/>\s+</g, "><").replace(/\s+/g, " ").trim();
6
+ }
7
+
8
+ describe("tag", () => {
9
+ test("renders a self closing tag", () => {
10
+ const builder = new HTMLBuilder();
11
+
12
+ const result = builder.tag("img", null, { src: "/some-image.jpg" });
13
+
14
+ expect(normalizeHTML(result)).toEqual(
15
+ normalizeHTML('<img src="/some-image.jpg" />')
16
+ );
17
+ });
18
+
19
+ test("renders a label tag", () => {
20
+ const builder = new HTMLBuilder();
21
+
22
+ const result = builder.tag("label", "Heelo", { for: "some-input-id" });
23
+
24
+ expect(normalizeHTML(result)).toEqual(
25
+ normalizeHTML('<label for="some-input-id">Heelo</label>')
26
+ );
27
+ });
28
+
29
+ test("renders a textarea tag", () => {
30
+ const builder = new HTMLBuilder();
31
+
32
+ const result = builder.tag(
33
+ "textarea",
34
+ undefined,
35
+ { id: "some-input-id", value: "Text?" },
36
+ { nonVoid: true }
37
+ );
38
+
39
+ expect(normalizeHTML(result)).toEqual(
40
+ normalizeHTML('<textarea id="some-input-id" value="Text?"></textarea>')
41
+ );
42
+ });
43
+ });
44
+ });