1.2.0 - Has been implemented the "user-info" method exposed by the Tuitio API.

master
Tudor Stanciu 2023-03-28 19:20:32 +03:00
parent 5804ca084d
commit 13083aecf7
15 changed files with 112 additions and 51 deletions

View File

@ -39,3 +39,4 @@ All tests in the package can be executed by running: `npm test`.
1.0.3 - Added LICENSE file 1.0.3 - Added LICENSE file
1.0.4 - TuitioState's token property can be null 1.0.4 - TuitioState's token property can be null
1.1.0 - In this version, the account logout method and the latest changes published by Tuitio were implemented. 1.1.0 - In this version, the account logout method and the latest changes published by Tuitio were implemented.
1.2.0 - Has been implemented the "user-info" method exposed by the Tuitio API.

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "@flare/tuitio-client", "name": "@flare/tuitio-client",
"version": "1.1.0", "version": "1.2.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@flare/tuitio-client", "name": "@flare/tuitio-client",
"version": "1.1.0", "version": "1.2.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@flare/js-utils": "^1.0.3", "@flare/js-utils": "^1.0.3",

View File

@ -1,6 +1,6 @@
{ {
"name": "@flare/tuitio-client", "name": "@flare/tuitio-client",
"version": "1.1.0", "version": "1.2.0",
"description": "Tuitio client is an npm package written in typescript that facilitates the integration of a javascript application with Tuitio.", "description": "Tuitio client is an npm package written in typescript that facilitates the integration of a javascript application with Tuitio.",
"main": "./lib/index.js", "main": "./lib/index.js",
"types": "./lib/index.d.ts", "types": "./lib/index.d.ts",

View File

@ -2,7 +2,7 @@
import { getUrlTemplates } from "../config"; import { getUrlTemplates } from "../config";
import { TuitioClient } from "../client"; import { TuitioClient } from "../client";
import type { TuitioLoginResponse } from "../client"; import type { TuitioLoginResponse } from "../types";
test("Get url templates", () => { test("Get url templates", () => {
const result = getUrlTemplates("https://test.com/api"); const result = getUrlTemplates("https://test.com/api");

View File

@ -5,7 +5,8 @@
// Copyright (c) 2023 Tudor Stanciu // Copyright (c) 2023 Tudor Stanciu
import axios from "axios"; import axios from "axios";
import { TuitioClient, fetch } from "../client"; import { TuitioClient } from "../client";
import { fetch } from "../state";
jest.mock("axios"); jest.mock("axios");

View File

@ -5,7 +5,8 @@
// Copyright (c) 2023 Tudor Stanciu // Copyright (c) 2023 Tudor Stanciu
import axios from "axios"; import axios from "axios";
import { TuitioClient, fetch } from "../client"; import { TuitioClient } from "../client";
import { fetch } from "../state";
import { localStorage } from "@flare/js-utils"; import { localStorage } from "@flare/js-utils";
import { storageKeys } from "../constants"; import { storageKeys } from "../constants";

View File

@ -4,7 +4,7 @@
// Copyright (c) 2023 Tudor Stanciu // Copyright (c) 2023 Tudor Stanciu
import { fetch } from "../client"; import { fetch } from "../state";
test("Tuitio empty storage", () => { test("Tuitio empty storage", () => {
const result = fetch(); const result = fetch();

View File

@ -1,6 +1,6 @@
// Copyright (c) 2023 Tudor Stanciu // Copyright (c) 2023 Tudor Stanciu
import { combineUrls, isValidURL } from "../utils"; import { combineUrls, isValidURL } from "../../utils/validations";
test("Combine urls with trailing slash", () => { test("Combine urls with trailing slash", () => {
const result = combineUrls("https://test.com/api/", "/test"); const result = combineUrls("https://test.com/api/", "/test");

View File

@ -1,33 +1,15 @@
// Copyright (c) 2023 Tudor Stanciu // Copyright (c) 2023 Tudor Stanciu
import axios from "axios"; import { request } from "./utils/axios";
import { localStorage } from "@flare/js-utils"; import { localStorage } from "@flare/js-utils";
import { storageKeys } from "./constants"; import { storageKeys } from "./constants";
import { getUrlTemplates } from "./config"; import { getUrlTemplates } from "./config";
import { isValidURL } from "./utils"; import { isValidURL } from "./utils/validations";
import type { UrlTemplates } from "./config"; import type { UrlTemplates } from "./config";
import type { TuitioLoginResponse, TuitioLogoutResponse, TuitioUserInfoResponse } from "./types";
const { setItem, getItem, removeItem } = localStorage; const { setItem, getItem, removeItem } = localStorage;
async function request(url: string, method: string) {
try {
const res = await axios.request({ url, method });
return res.data;
} catch (error: any) {
if (error.response && error.response.data) {
const { detail, title } = error.response.data;
throw {
...error.response.data,
message: detail || title
};
}
throw error;
}
}
export type TuitioLoginResponse = { result: { token: string; expiresIn: number; validUntil: Date } | null; error: string | null };
export type TuitioLogoutResponse = { result: { userId: number; userName: string; logoutDate: Date } | null; error: string };
class TuitioClient { class TuitioClient {
tuitioUrl: string; tuitioUrl: string;
urlTemplates: UrlTemplates; urlTemplates: UrlTemplates;
@ -67,22 +49,13 @@ class TuitioClient {
} }
return response; return response;
} }
async getUserInfo(): Promise<TuitioUserInfoResponse> {
const url = this.urlTemplates.userInfo;
const response = await request(url, "get");
return response;
}
} }
export type TuitioState = { token: string | null; validUntil: Date | null; userName: string | null }; export { TuitioClient };
const defaultTuitioState: TuitioState = { token: null, validUntil: null, userName: null };
const fetch = (): TuitioState => {
const authData = getItem(storageKeys.AUTH_DATA);
if (!authData) return defaultTuitioState;
const { token, validUntil, userName } = authData;
const data: TuitioState = {
token,
validUntil,
userName
};
return data;
};
export { TuitioClient, fetch };
export default TuitioClient; export default TuitioClient;

View File

@ -1,15 +1,17 @@
// Copyright (c) 2023 Tudor Stanciu // Copyright (c) 2023 Tudor Stanciu
import { combineUrls } from "./utils"; import { combineUrls } from "./utils/validations";
export type UrlTemplates = { export type UrlTemplates = {
login: string; login: string;
logout: string; logout: string;
userInfo: string;
}; };
const getUrlTemplates = (tuitioUrl: string): UrlTemplates => ({ const getUrlTemplates = (tuitioUrl: string): UrlTemplates => ({
login: combineUrls(tuitioUrl, "/account/login?UserName={username}&Password={password}"), login: combineUrls(tuitioUrl, "/account/login?UserName={username}&Password={password}"),
logout: combineUrls(tuitioUrl, "/account/logout?Token={token}") logout: combineUrls(tuitioUrl, "/account/logout?Token={token}"),
userInfo: combineUrls(tuitioUrl, "/connect/user-info")
}); });
export { getUrlTemplates }; export { getUrlTemplates };

View File

@ -1,8 +1,9 @@
// Copyright (c) 2023 Tudor Stanciu // Copyright (c) 2023 Tudor Stanciu
import { TuitioClient, fetch } from "./client"; import { TuitioClient } from "./client";
import type { TuitioLoginResponse, TuitioLogoutResponse, TuitioState } from "./client"; import { fetch } from "./state";
export * from "./types";
export { TuitioClient, fetch }; export { TuitioClient, fetch };
export type { TuitioLoginResponse, TuitioLogoutResponse, TuitioState };
export default TuitioClient; export default TuitioClient;

23
src/state.ts Normal file
View File

@ -0,0 +1,23 @@
// Copyright (c) 2023 Tudor Stanciu
import { localStorage } from "@flare/js-utils";
import { storageKeys } from "./constants";
import type { TuitioState } from "./types";
const { getItem } = localStorage;
const defaultTuitioState: TuitioState = { token: null, validUntil: null, userName: null };
const fetch = (): TuitioState => {
const authData = getItem(storageKeys.AUTH_DATA);
if (!authData) return defaultTuitioState;
const { token, validUntil, userName } = authData;
const data: TuitioState = {
token,
validUntil,
userName
};
return data;
};
export { fetch };

25
src/types.ts Normal file
View File

@ -0,0 +1,25 @@
export type TuitioLoginResponse = { result: { token: string; expiresIn: number; validUntil: Date } | null; error: string | null };
export type TuitioLogoutResponse = { result: { userId: number; userName: string; logoutDate: Date } | null; error: string };
export type TuitioState = { token: string | null; validUntil: Date | null; userName: string | null };
export type TuitioUserContactOption = {
id: number;
contactTypeCode: string;
contactTypeName: string;
contactValue: string;
};
export type TuitioUserInfoResponse = {
userId: number;
userName: string;
firstName: string;
lastName: string;
email: string;
profilePictureUrl: string;
securityStamp: string;
creationDate: Date;
failedLoginAttempts: number;
lastLoginDate: Date;
claim?: object;
contactOptions?: [TuitioUserContactOption];
};

34
src/utils/axios.ts Normal file
View File

@ -0,0 +1,34 @@
// Copyright (c) 2023 Tudor Stanciu
import axios, { AxiosHeaders } from "axios";
import { fetch } from "../state";
function getHeaders(): AxiosHeaders {
const { token } = fetch();
const headers = new AxiosHeaders({
"Content-Type": "application/json"
});
if (token) {
headers["Authorization"] = `Tuitio ${token}`;
}
return headers;
}
async function request(url: string, method: string) {
const headers = getHeaders();
try {
const res = await axios.request({ url, method, headers });
return res.data;
} catch (error: any) {
if (error.response && error.response.data) {
const { detail, title } = error.response.data;
throw {
...error.response.data,
message: detail || title
};
}
throw error;
}
}
export { request };