Skip to content

Commit 5cca867

Browse files
committed
feat: Refactor AuthService to use ApiService for API calls and update tests accordingly
1 parent c6559d2 commit 5cca867

File tree

2 files changed

+89
-98
lines changed

2 files changed

+89
-98
lines changed

packages/user/src/auth-services.ts

Lines changed: 54 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Refactored from legacy AngularJS service. All SPA dependencies removed.
77
* Configuration is injected via constructor.
88
*/
9-
import type { ApiResult, RestApiResult } from '@mixcore/api';
9+
import type { ApiResult, RestApiResult, ApiService } from '@mixcore/api';
1010
import type { CryptoService } from '@mixcore/shared';
1111
import type { ConfigurationService } from '@mixcore/config';
1212

@@ -16,22 +16,16 @@ import type { ConfigurationService } from '@mixcore/config';
1616
* @public
1717
*/
1818
export interface AuthServiceConfig {
19-
/** Base URL for API requests */
20-
apiBaseUrl: string;
21-
/** Optional API key for authentication */
22-
apiKey?: string;
19+
/** ApiService instance for making API calls */
20+
apiService: ApiService;
2321
/** AES encryption function from shared domain */
24-
encryptAES: CryptoService['encryptAES'];
22+
encryptAES?: CryptoService['encryptAES'];
2523
/** Update authentication data in storage (shared/config) */
26-
updateAuthData: (data: any) => void;
24+
updateAuthData?: (data: any) => void;
2725
/** Fill authentication data from storage (shared/config) */
28-
fillAuthData: () => Promise<any>;
26+
fillAuthData?: () => Promise<any>;
2927
/** Initialize all settings after login (config) */
3028
initAllSettings: () => Promise<void>;
31-
/** Generic API result fetcher (api domain) */
32-
getApiResult: (req: any) => Promise<ApiResult>;
33-
/** REST API result fetcher (api domain) */
34-
getRestApiResult: (req: any, ...args: any[]) => Promise<RestApiResult>;
3529
/** Optional localStorage implementation (shared) */
3630
localStorage?: Storage;
3731
/** Optional plugin hooks for extensibility */
@@ -78,11 +72,7 @@ export class AuthService {
7872
*/
7973
async saveRegistration(registration: Record<string, any>): Promise<ApiResult> {
8074
try {
81-
return await this.config.getApiResult({
82-
method: 'POST',
83-
url: '/account/register',
84-
data: registration,
85-
});
75+
return await this.config.apiService.post('/account/register', registration);
8676
} catch (err) {
8777
throw new Error('Registration failed: ' + (err as Error).message);
8878
}
@@ -97,11 +87,8 @@ export class AuthService {
9787
*/
9888
async forgotPassword(data: Record<string, any>): Promise<RestApiResult> {
9989
try {
100-
return await this.config.getRestApiResult({
101-
method: 'POST',
102-
url: '/account/forgot-password',
103-
data: JSON.stringify(data),
104-
});
90+
const result = await this.config.apiService.post('/account/forgot-password', data);
91+
return result as RestApiResult;
10592
} catch (err) {
10693
throw new Error('Forgot password failed: ' + (err as Error).message);
10794
}
@@ -116,11 +103,8 @@ export class AuthService {
116103
*/
117104
async resetPassword(data: Record<string, any>): Promise<RestApiResult> {
118105
try {
119-
return await this.config.getRestApiResult({
120-
method: 'POST',
121-
url: '/account/reset-password',
122-
data: JSON.stringify(data),
123-
});
106+
const result = await this.config.apiService.post('/account/reset-password', data);
107+
return result as RestApiResult;
124108
} catch (err) {
125109
throw new Error('Reset password failed: ' + (err as Error).message);
126110
}
@@ -144,6 +128,12 @@ export class AuthService {
144128
});
145129
}
146130

131+
/**
132+
* Unsecure login (framework-agnostic, legacy-compatible)
133+
* Only requires: getRestApiResult, updateAuthData, initAllSettings, plugins (optional)
134+
* @param loginData Login credentials (email, userName, phoneNumber, password, rememberMe, returnUrl)
135+
* @returns RestApiResult
136+
*/
147137
async loginUnsecure(loginData: {
148138
email: string;
149139
userName: string;
@@ -152,23 +142,33 @@ export class AuthService {
152142
rememberMe: boolean;
153143
returnUrl: string;
154144
}): Promise<RestApiResult> {
155-
const req = {
156-
method: 'POST',
157-
url: '/api/v2/rest/auth/user/login-unsecure',
158-
data: JSON.stringify(loginData),
159-
};
160-
const resp = await this.config.getRestApiResult(req, true);
161-
if (resp.isSucceed) {
162-
this.config.updateAuthData(resp.data);
163-
await this.config.initAllSettings();
164-
// Plugin hook
165-
if (this.config.plugins) {
166-
for (const plugin of this.config.plugins) {
167-
if (plugin.onLoginSuccess) await plugin.onLoginSuccess(resp);
145+
// Legacy-compatible: always POST, expects JSON, handles errors gracefully
146+
try {
147+
const resp = await this.config.apiService.post(
148+
'/api/v2/rest/auth/user/login-unsecure',
149+
loginData
150+
) as RestApiResult;
151+
152+
if (resp && resp.isSucceed) {
153+
// Patch/normalize response if needed (legacy: resp.data)
154+
this.config.updateAuthData(resp.data);
155+
await this.config.initAllSettings();
156+
// Plugin hook
157+
if (this.config.plugins) {
158+
for (const plugin of this.config.plugins) {
159+
if (plugin.onLoginSuccess) await plugin.onLoginSuccess(resp);
160+
}
168161
}
169162
}
163+
return resp;
164+
} catch (err) {
165+
// Legacy: error normalization
166+
return {
167+
isSucceed: false,
168+
errors: [(err as Error).message],
169+
data: null
170+
} as RestApiResult;
170171
}
171-
return resp;
172172
}
173173

174174
/**
@@ -187,12 +187,10 @@ export class AuthService {
187187
externalAccessToken: loginData.accessToken,
188188
};
189189
const message = this.config.encryptAES(JSON.stringify(data));
190-
const req = {
191-
method: 'POST',
192-
url: '/account/external-login',
193-
data: JSON.stringify({ message }),
194-
};
195-
const resp = await this.config.getRestApiResult(req, true);
190+
const resp = await this.config.apiService.post(
191+
'/account/external-login',
192+
{ message }
193+
) as RestApiResult;
196194
if (resp.isSucceed) {
197195
this.config.updateAuthData(resp.data);
198196
await this.config.initAllSettings();
@@ -250,12 +248,10 @@ export class AuthService {
250248
*/
251249
async refreshToken(id: string, accessToken: string): Promise<ApiResult | void> {
252250
if (!id) return this.logOut();
253-
const req = {
254-
method: 'POST',
255-
url: '/account/refresh-token',
256-
data: JSON.stringify({ refreshToken: id, accessToken }),
257-
};
258-
const resp = await this.config.getApiResult(req);
251+
const resp = await this.config.apiService.post(
252+
'/account/refresh-token',
253+
{ refreshToken: id, accessToken }
254+
);
259255
if (resp.isSucceed) {
260256
return this.config.updateAuthData(resp.data);
261257
} else {
@@ -273,39 +269,22 @@ export class AuthService {
273269
}
274270

275271
async getRoles(): Promise<ApiResult> {
276-
return this.config.getApiResult({
277-
method: 'GET',
278-
url: '/api/v2/rest/auth/role'
279-
});
272+
return this.config.apiService.get('/api/v2/rest/auth/role');
280273
}
281274

282275
async createRole(data: {description: string}): Promise<ApiResult> {
283-
return this.config.getApiResult({
284-
method: 'POST',
285-
url: '/api/v2/rest/auth/role/create',
286-
data
287-
});
276+
return this.config.apiService.post('/api/v2/rest/auth/role/create', data);
288277
}
289278

290279
async updateRole(id: string, data: {description: string}): Promise<ApiResult> {
291-
return this.config.getApiResult({
292-
method: 'PUT',
293-
url: `/api/v2/rest/auth/role/${id}`,
294-
data
295-
});
280+
return this.config.apiService.post(`/api/v2/rest/auth/role/${id}`, data);
296281
}
297282

298283
async deleteRole(id: string): Promise<ApiResult> {
299-
return this.config.getApiResult({
300-
method: 'DELETE',
301-
url: `/api/v2/rest/auth/role/${id}`
302-
});
284+
return this.config.apiService.delete(`/api/v2/rest/auth/role/${id}`);
303285
}
304286

305287
async getDefaultRole(): Promise<ApiResult> {
306-
return this.config.getApiResult({
307-
method: 'GET',
308-
url: '/api/v2/rest/auth/role/default'
309-
});
288+
return this.config.apiService.get('/api/v2/rest/auth/role/default');
310289
}
311290
}

packages/user/tests/auth-services.test.ts

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,35 @@
11
import { AuthService, AuthServiceConfig } from '../src/auth-services';
2+
import type { ApiService, ApiResult, RestApiResult } from '@mixcore/api';
3+
import { ApiService } from '@mixcore/api';
24

35
describe('AuthService', () => {
6+
const mockApiService: jest.Mocked<ApiService> = {
7+
get: jest.fn(async (endpoint: string, params?: Record<string, any>) => ({
8+
isSucceed: true,
9+
data: {
10+
id: '1',
11+
description: 'Test Role'
12+
}
13+
})),
14+
post: jest.fn(async (endpoint: string, data: any, options?: { isFormData?: boolean }) => ({
15+
isSucceed: true,
16+
data: {
17+
id: '1',
18+
description: 'Test Role'
19+
}
20+
})),
21+
delete: jest.fn(async (endpoint: string) => ({
22+
isSucceed: true,
23+
data: {
24+
id: '1',
25+
description: 'Test Role'
26+
}
27+
})),
28+
use: jest.fn(),
29+
} as jest.Mocked<ApiService>;
30+
431
const config: AuthServiceConfig = {
5-
apiBaseUrl: 'https://mixcore.net',
32+
apiService: mockApiService,
633
encryptAES: (data) => data, // mock encryption
734
updateAuthData: jest.fn(),
835
fillAuthData: jest.fn(async () => ({
@@ -17,33 +44,19 @@ describe('AuthService', () => {
1744
}
1845
})),
1946
initAllSettings: jest.fn(async () => {}),
20-
getApiResult: jest.fn(async (req) => ({
21-
isSucceed: true,
22-
data: {
23-
id: '1',
24-
description: 'Test Role'
25-
}
26-
})),
27-
getRestApiResult: jest.fn(async (req) => ({
28-
isSucceed: true,
29-
data: {
30-
id: '1',
31-
description: 'Test Role'
32-
}
33-
})),
3447
localStorage: { removeItem: jest.fn() } as any,
3548
};
3649
const service = new AuthService(config);
3750

3851
// Existing auth tests
3952
it('should call saveRegistration', async () => {
4053
await service.saveRegistration({});
41-
expect(config.getApiResult).toHaveBeenCalled();
54+
expect(mockApiService.post).toHaveBeenCalledWith('/account/register', {});
4255
});
4356

4457
it('should call forgotPassword', async () => {
4558
await service.forgotPassword({});
46-
expect(config.getRestApiResult).toHaveBeenCalled();
59+
expect(mockApiService.post).toHaveBeenCalledWith('/account/forgot-password', {});
4760
});
4861

4962
it('should call login and updateAuthData', async () => {
@@ -60,18 +73,17 @@ describe('AuthService', () => {
6073
rememberMe: true,
6174
returnUrl: '/home'
6275
});
63-
expect(config.getRestApiResult).toHaveBeenCalledWith({
64-
method: 'POST',
65-
url: '/api/v2/rest/auth/user/login-unsecure',
66-
data: JSON.stringify({
76+
expect(mockApiService.post).toHaveBeenCalledWith(
77+
'/api/v2/rest/auth/user/login-unsecure',
78+
{
6779
6880
userName: 'user',
6981
phoneNumber: '123456789',
7082
password: 'pass',
7183
rememberMe: true,
7284
returnUrl: '/home'
73-
})
74-
}, true);
85+
}
86+
);
7587
expect(config.updateAuthData).toHaveBeenCalled();
7688
});
7789

0 commit comments

Comments
 (0)