mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-15 11:37:57 +01:00
JWT impl.
This commit is contained in:
parent
7a4b5212d9
commit
cbca2e6184
@ -39,7 +39,8 @@
|
|||||||
"react-query": "^3.39.1",
|
"react-query": "^3.39.1",
|
||||||
"react-redux": "^7.2.2",
|
"react-redux": "^7.2.2",
|
||||||
"react-router-dom": "^6.4.3",
|
"react-router-dom": "^6.4.3",
|
||||||
"styled-components": "^5.3.6"
|
"styled-components": "^5.3.6",
|
||||||
|
"universal-cookie": "^7.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@formatjs/cli": "^6.0.4",
|
"@formatjs/cli": "^6.0.4",
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
|
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="<%=PUBLIC_URL%>/favicon.ico" />
|
<link rel="icon" href="<%=PUBLIC_URL%>/favicon.ico" />
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@100;200;300;400;600&display=swap" rel="stylesheet" rel="preload"/>
|
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@100;200;300;400;600&display=swap"
|
||||||
|
rel="stylesheet" rel="preload" />
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width" />
|
<meta name="viewport" content="width=device-width" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
@ -26,6 +27,20 @@
|
|||||||
<meta property="og:url" content="https://www.wisemapping.com" />
|
<meta property="og:url" content="https://www.wisemapping.com" />
|
||||||
<meta property="og:site_name" content="WiseMapping" />
|
<meta property="og:site_name" content="WiseMapping" />
|
||||||
|
|
||||||
|
<script>
|
||||||
|
if ('<%=CLIENT_TYPE%>' === 'rest');
|
||||||
|
{
|
||||||
|
window.serverconfig = {
|
||||||
|
apiBaseUrl: 'http://localhost:3000',
|
||||||
|
analyticsAccount: 'G-RSDEJH16YM',
|
||||||
|
clientType: 'rest',
|
||||||
|
recaptcha2Enabled: true,
|
||||||
|
recaptcha2SiteKey: '6Lcat08kAAAAAIP-HjhzIa-Yq21PHgGa_ADWc-Ro',
|
||||||
|
googleOauth2Url: 'https://accounts.google.com/o/oauth2/v2/auth?redirect_uri=https://app.wisemapping.com/c/registration-google&prompt=consent&response_type=code&client_id=625682766634-cocbbbbb403iuvps1evecdk6d7phvbkf.apps.googleusercontent.com&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&access_type=offline&state=wisemapping&include_granted_scopes=true'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
window.errorMvcView = '';
|
||||||
|
</script>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
manifest.json provides metadata used when your web app is installed on a
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
import { Locale, LocaleCode } from '../app-i18n';
|
import { Locale, LocaleCode } from '../app-i18n';
|
||||||
|
|
||||||
|
export type JwtAuth = {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type NewUser = {
|
export type NewUser = {
|
||||||
email: string;
|
email: string;
|
||||||
firstname: string;
|
firstname: string;
|
||||||
@ -85,6 +90,8 @@ export type ForgotPasswordResult = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface Client {
|
interface Client {
|
||||||
|
login(auth: JwtAuth): Promise<void>;
|
||||||
|
|
||||||
deleteAccount(): Promise<void>;
|
deleteAccount(): Promise<void>;
|
||||||
importMap(model: ImportMapInfo): Promise<number>;
|
importMap(model: ImportMapInfo): Promise<number>;
|
||||||
createMap(map: BasicMapInfo): Promise<number>;
|
createMap(map: BasicMapInfo): Promise<number>;
|
||||||
|
@ -26,8 +26,10 @@ import Client, {
|
|||||||
Permission,
|
Permission,
|
||||||
Oauth2CallbackResult,
|
Oauth2CallbackResult,
|
||||||
ForgotPasswordResult,
|
ForgotPasswordResult,
|
||||||
|
JwtAuth,
|
||||||
} from '..';
|
} from '..';
|
||||||
import { LocaleCode, localeFromStr } from '../../app-i18n';
|
import { LocaleCode, localeFromStr } from '../../app-i18n';
|
||||||
|
import Cookies from 'universal-cookie';
|
||||||
|
|
||||||
const label1: Label = {
|
const label1: Label = {
|
||||||
id: 1,
|
id: 1,
|
||||||
@ -127,6 +129,18 @@ class MockClient implements Client {
|
|||||||
this.labels = [label1, label2, label3];
|
this.labels = [label1, label2, label3];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
login(auth: JwtAuth): Promise<void> {
|
||||||
|
const cookies = new Cookies();
|
||||||
|
cookies.set('jwt-token-mock', auth.email, { path: '/' });
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _jwtToken(): string | undefined {
|
||||||
|
// Set cookie on session ...
|
||||||
|
const cookies = new Cookies();
|
||||||
|
return cookies.get('jwt-token-mock');
|
||||||
|
}
|
||||||
|
|
||||||
fetchStarred(id: number): Promise<boolean> {
|
fetchStarred(id: number): Promise<boolean> {
|
||||||
return Promise.resolve(Boolean(this.maps.find((m) => m.id == id)?.starred));
|
return Promise.resolve(Boolean(this.maps.find((m) => m.id == id)?.starred));
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,11 @@ import Client, {
|
|||||||
Permission,
|
Permission,
|
||||||
Oauth2CallbackResult,
|
Oauth2CallbackResult,
|
||||||
ForgotPasswordResult,
|
ForgotPasswordResult,
|
||||||
|
JwtAuth,
|
||||||
} from '..';
|
} from '..';
|
||||||
import { getCsrfToken } from '../../../utils';
|
import { getCsrfToken } from '../../../utils';
|
||||||
import { LocaleCode, localeFromStr } from '../../app-i18n';
|
import { LocaleCode, localeFromStr } from '../../app-i18n';
|
||||||
|
import Cookies from 'universal-cookie';
|
||||||
|
|
||||||
export default class RestClient implements Client {
|
export default class RestClient implements Client {
|
||||||
private baseUrl: string;
|
private baseUrl: string;
|
||||||
@ -32,18 +34,64 @@ export default class RestClient implements Client {
|
|||||||
constructor(baseUrl: string) {
|
constructor(baseUrl: string) {
|
||||||
this.baseUrl = baseUrl;
|
this.baseUrl = baseUrl;
|
||||||
this.axios = axios.create({ maxRedirects: 0 });
|
this.axios = axios.create({ maxRedirects: 0 });
|
||||||
|
|
||||||
|
// Configure request interceptors ...
|
||||||
|
this.axios.interceptors.request.use((config) => {
|
||||||
|
if (config.headers) {
|
||||||
|
// JWT Token ...
|
||||||
|
const jwtToken = this._jwtToken();
|
||||||
|
if (jwtToken) {
|
||||||
|
config.headers['Authorization'] = jwtToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Csrf token ...
|
||||||
const csrfToken = getCsrfToken();
|
const csrfToken = getCsrfToken();
|
||||||
if (csrfToken) {
|
if (csrfToken) {
|
||||||
this.axios.defaults.headers['X-CSRF-TOKEN'] = csrfToken;
|
config.headers['X-CSRF-TOKEN'] = csrfToken;
|
||||||
} else {
|
} else {
|
||||||
console.warn('csrf token not found in html head');
|
console.warn('csrf token not found in html head');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Process response globally ...
|
||||||
this.axios.interceptors.response.use(
|
this.axios.interceptors.response.use(
|
||||||
(r) => r,
|
(response) => response,
|
||||||
(r) => this.checkResponseForSessionExpired(r),
|
(respoonse) => this.checkResponseForSessionExpired(respoonse),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
login(model: JwtAuth): Promise<void> {
|
||||||
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
|
this.axios
|
||||||
|
.post(`${this.baseUrl}/api/restful/authenticate`, model, {
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
const token = response.data;
|
||||||
|
// Set jwt token on cookie ...
|
||||||
|
const cookies = new Cookies();
|
||||||
|
cookies.set('jwt-auth-token', token, { path: '/', maxAge: 604800 });
|
||||||
|
|
||||||
|
success();
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
const errorInfo = this.parseResponseOnError(error.response);
|
||||||
|
reject(errorInfo);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
return new Promise(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _jwtToken(): string | null {
|
||||||
|
// Set cookie on session ...
|
||||||
|
const cookies = new Cookies();
|
||||||
|
const token = cookies.get('jwt-auth-token');
|
||||||
|
return token ? `Bearer ${token}` : null;
|
||||||
|
}
|
||||||
|
|
||||||
private _onSessionExpired: () => void;
|
private _onSessionExpired: () => void;
|
||||||
onSessionExpired(callback?: () => void): () => void {
|
onSessionExpired(callback?: () => void): () => void {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
@ -61,9 +109,12 @@ export default class RestClient implements Client {
|
|||||||
deleteMapPermission(id: number, email: string): Promise<void> {
|
deleteMapPermission(id: number, email: string): Promise<void> {
|
||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.delete(`${this.baseUrl}/c/restful/maps/${id}/collabs?email=${encodeURIComponent(email)}`, {
|
.delete(
|
||||||
|
`${this.baseUrl}/api/restful/maps/${id}/collabs?email=${encodeURIComponent(email)}`,
|
||||||
|
{
|
||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
},
|
||||||
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
success();
|
success();
|
||||||
})
|
})
|
||||||
@ -78,7 +129,7 @@ export default class RestClient implements Client {
|
|||||||
fetchStarred(id: number): Promise<boolean> {
|
fetchStarred(id: number): Promise<boolean> {
|
||||||
const handler = (success: (starred: boolean) => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: (starred: boolean) => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.get(`${this.baseUrl}/c/restful/maps/${id}/starred`, {
|
.get(`${this.baseUrl}/api/restful/maps/${id}/starred`, {
|
||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@ -98,7 +149,7 @@ export default class RestClient implements Client {
|
|||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.put(
|
.put(
|
||||||
`${this.baseUrl}/c/restful/maps/${id}/collabs/`,
|
`${this.baseUrl}/api/restful/maps/${id}/collabs/`,
|
||||||
{
|
{
|
||||||
message: message,
|
message: message,
|
||||||
collaborations: permissions,
|
collaborations: permissions,
|
||||||
@ -123,7 +174,7 @@ export default class RestClient implements Client {
|
|||||||
reject: (error: ErrorInfo) => void,
|
reject: (error: ErrorInfo) => void,
|
||||||
) => {
|
) => {
|
||||||
this.axios
|
this.axios
|
||||||
.get(`${this.baseUrl}/c/restful/maps/${id}/collabs`, {
|
.get(`${this.baseUrl}/api/restful/maps/${id}/collabs`, {
|
||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@ -150,7 +201,7 @@ export default class RestClient implements Client {
|
|||||||
deleteAccount(): Promise<void> {
|
deleteAccount(): Promise<void> {
|
||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.delete(`${this.baseUrl}/c/restful/account`, {
|
.delete(`${this.baseUrl}/api/restful/account`, {
|
||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -167,11 +218,11 @@ export default class RestClient implements Client {
|
|||||||
updateAccountInfo(firstname: string, lastname: string): Promise<void> {
|
updateAccountInfo(firstname: string, lastname: string): Promise<void> {
|
||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.put(`${this.baseUrl}/c/restful/account/firstname`, firstname, {
|
.put(`${this.baseUrl}/api/restful/account/firstname`, firstname, {
|
||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return this.axios.put(`${this.baseUrl}/c/restful/account/lastname`, lastname, {
|
return this.axios.put(`${this.baseUrl}/api/restful/account/lastname`, lastname, {
|
||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@ -190,7 +241,7 @@ export default class RestClient implements Client {
|
|||||||
updateAccountPassword(pasword: string): Promise<void> {
|
updateAccountPassword(pasword: string): Promise<void> {
|
||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.put(`${this.baseUrl}/c/restful/account/password`, pasword, {
|
.put(`${this.baseUrl}/api/restful/account/password`, pasword, {
|
||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -207,7 +258,7 @@ export default class RestClient implements Client {
|
|||||||
updateAccountLanguage(locale: LocaleCode): Promise<void> {
|
updateAccountLanguage(locale: LocaleCode): Promise<void> {
|
||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.put(`${this.baseUrl}/c/restful/account/locale`, locale, {
|
.put(`${this.baseUrl}/api/restful/account/locale`, locale, {
|
||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -229,7 +280,7 @@ export default class RestClient implements Client {
|
|||||||
const handler = (success: (mapId: number) => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: (mapId: number) => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.post(
|
.post(
|
||||||
`${this.baseUrl}/c/restful/maps?title=${encodeURIComponent(
|
`${this.baseUrl}/api/restful/maps?title=${encodeURIComponent(
|
||||||
model.title,
|
model.title,
|
||||||
)}&description=${encodeURIComponent(model.description ? model.description : '')}`,
|
)}&description=${encodeURIComponent(model.description ? model.description : '')}`,
|
||||||
model.content,
|
model.content,
|
||||||
@ -253,7 +304,7 @@ export default class RestClient implements Client {
|
|||||||
reject: (error: ErrorInfo) => void,
|
reject: (error: ErrorInfo) => void,
|
||||||
) => {
|
) => {
|
||||||
this.axios
|
this.axios
|
||||||
.get(`${this.baseUrl}/c/restful/account`, {
|
.get(`${this.baseUrl}/api/restful/account`, {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@ -278,7 +329,7 @@ export default class RestClient implements Client {
|
|||||||
deleteMaps(ids: number[]): Promise<void> {
|
deleteMaps(ids: number[]): Promise<void> {
|
||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.delete(`${this.baseUrl}/c/restful/maps/batch?ids=${ids.join()}`, {
|
.delete(`${this.baseUrl}/api/restful/maps/batch?ids=${ids.join()}`, {
|
||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -296,7 +347,7 @@ export default class RestClient implements Client {
|
|||||||
updateMapToPublic(id: number, isPublic: boolean): Promise<void> {
|
updateMapToPublic(id: number, isPublic: boolean): Promise<void> {
|
||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.put(`${this.baseUrl}/c/restful/maps/${id}/publish`, isPublic.toString(), {
|
.put(`${this.baseUrl}/api/restful/maps/${id}/publish`, isPublic.toString(), {
|
||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -313,7 +364,7 @@ export default class RestClient implements Client {
|
|||||||
revertHistory(id: number, hid: number): Promise<void> {
|
revertHistory(id: number, hid: number): Promise<void> {
|
||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.post(`${this.baseUrl}/c/restful/maps/${id}/history/${hid}`, null, {
|
.post(`${this.baseUrl}/api/restful/maps/${id}/history/${hid}`, null, {
|
||||||
headers: { 'Content-Type': 'text/pain' },
|
headers: { 'Content-Type': 'text/pain' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -333,7 +384,7 @@ export default class RestClient implements Client {
|
|||||||
reject: (error: ErrorInfo) => void,
|
reject: (error: ErrorInfo) => void,
|
||||||
) => {
|
) => {
|
||||||
this.axios
|
this.axios
|
||||||
.get(`${this.baseUrl}/c/restful/maps/${id}/history/`, {
|
.get(`${this.baseUrl}/api/restful/maps/${id}/history/`, {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@ -358,12 +409,12 @@ export default class RestClient implements Client {
|
|||||||
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void> {
|
renameMap(id: number, basicInfo: BasicMapInfo): Promise<void> {
|
||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.put(`${this.baseUrl}/c/restful/maps/${id}/title`, basicInfo.title, {
|
.put(`${this.baseUrl}/api/restful/maps/${id}/title`, basicInfo.title, {
|
||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return this.axios.put(
|
return this.axios.put(
|
||||||
`${this.baseUrl}/c/restful/maps/${id}/description`,
|
`${this.baseUrl}/api/restful/maps/${id}/description`,
|
||||||
basicInfo.description || ' ',
|
basicInfo.description || ' ',
|
||||||
{ headers: { 'Content-Type': 'text/plain' } },
|
{ headers: { 'Content-Type': 'text/plain' } },
|
||||||
);
|
);
|
||||||
@ -385,10 +436,10 @@ export default class RestClient implements Client {
|
|||||||
const handler = (success: (mapId: number) => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: (mapId: number) => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.post(
|
.post(
|
||||||
`${this.baseUrl}/c/restful/maps?title=${encodeURIComponent(
|
`${this.baseUrl}/api/restful/maps?title=${encodeURIComponent(
|
||||||
model.title,
|
model.title,
|
||||||
)}&description=${encodeURIComponent(model.description ? model.description : '')}`,
|
)}&description=${encodeURIComponent(model.description ? model.description : '')}`,
|
||||||
null,
|
undefined,
|
||||||
{ headers: { 'Content-Type': 'application/json' } },
|
{ headers: { 'Content-Type': 'application/json' } },
|
||||||
)
|
)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@ -409,7 +460,7 @@ export default class RestClient implements Client {
|
|||||||
reject: (error: ErrorInfo) => void,
|
reject: (error: ErrorInfo) => void,
|
||||||
) => {
|
) => {
|
||||||
this.axios
|
this.axios
|
||||||
.get(`${this.baseUrl}/c/restful/maps/`, {
|
.get(`${this.baseUrl}/api/restful/maps/`, {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@ -443,7 +494,7 @@ export default class RestClient implements Client {
|
|||||||
registerNewUser(user: NewUser): Promise<void> {
|
registerNewUser(user: NewUser): Promise<void> {
|
||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.post(`${this.baseUrl}/service/users/`, JSON.stringify(user), {
|
.post(`${this.baseUrl}/api/restful/users/`, JSON.stringify(user), {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -461,7 +512,7 @@ export default class RestClient implements Client {
|
|||||||
deleteMap(id: number): Promise<void> {
|
deleteMap(id: number): Promise<void> {
|
||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.delete(`${this.baseUrl}/c/restful/maps/${id}`, {
|
.delete(`${this.baseUrl}/api/restful/maps/${id}`, {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -482,7 +533,7 @@ export default class RestClient implements Client {
|
|||||||
) => {
|
) => {
|
||||||
this.axios
|
this.axios
|
||||||
.put(
|
.put(
|
||||||
`${this.baseUrl}/service/users/resetPassword?email=${encodeURIComponent(email)}`,
|
`${this.baseUrl}/api/restful/users/resetPassword?email=${encodeURIComponent(email)}`,
|
||||||
null,
|
null,
|
||||||
{
|
{
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
@ -504,7 +555,7 @@ export default class RestClient implements Client {
|
|||||||
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number> {
|
duplicateMap(id: number, basicInfo: BasicMapInfo): Promise<number> {
|
||||||
const handler = (success: (mapId: number) => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: (mapId: number) => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.post(`${this.baseUrl}/c/restful/maps/${id}`, JSON.stringify(basicInfo), {
|
.post(`${this.baseUrl}/api/restful/maps/${id}`, JSON.stringify(basicInfo), {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@ -523,7 +574,7 @@ export default class RestClient implements Client {
|
|||||||
updateStarred(id: number, starred: boolean): Promise<void> {
|
updateStarred(id: number, starred: boolean): Promise<void> {
|
||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.put(`${this.baseUrl}/c/restful/maps/${id}/starred`, starred.toString(), {
|
.put(`${this.baseUrl}/api/restful/maps/${id}/starred`, starred.toString(), {
|
||||||
headers: { 'Content-Type': 'text/plain' },
|
headers: { 'Content-Type': 'text/plain' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -541,7 +592,7 @@ export default class RestClient implements Client {
|
|||||||
fetchLabels(): Promise<Label[]> {
|
fetchLabels(): Promise<Label[]> {
|
||||||
const handler = (success: (labels: Label[]) => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: (labels: Label[]) => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.get(`${this.baseUrl}/c/restful/labels/`, {
|
.get(`${this.baseUrl}/api/restful/labels/`, {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@ -569,7 +620,7 @@ export default class RestClient implements Client {
|
|||||||
const handler = (success: (labelId: number) => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: (labelId: number) => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.post(
|
.post(
|
||||||
`${this.baseUrl}/c/restful/labels`,
|
`${this.baseUrl}/api/restful/labels`,
|
||||||
JSON.stringify({ title, color, iconName: 'smile' }),
|
JSON.stringify({ title, color, iconName: 'smile' }),
|
||||||
{
|
{
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
@ -590,7 +641,7 @@ export default class RestClient implements Client {
|
|||||||
deleteLabel(id: number): Promise<void> {
|
deleteLabel(id: number): Promise<void> {
|
||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.delete(`${this.baseUrl}/c/restful/labels/${id}`)
|
.delete(`${this.baseUrl}/api/restful/labels/${id}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
success();
|
success();
|
||||||
})
|
})
|
||||||
@ -605,7 +656,7 @@ export default class RestClient implements Client {
|
|||||||
addLabelToMap(labelId: number, mapId: number): Promise<void> {
|
addLabelToMap(labelId: number, mapId: number): Promise<void> {
|
||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.post(`${this.baseUrl}/c/restful/maps/${mapId}/labels`, JSON.stringify(labelId), {
|
.post(`${this.baseUrl}/api/restful/maps/${mapId}/labels`, JSON.stringify(labelId), {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -622,7 +673,7 @@ export default class RestClient implements Client {
|
|||||||
deleteLabelFromMap(labelId: number, mapId: number): Promise<void> {
|
deleteLabelFromMap(labelId: number, mapId: number): Promise<void> {
|
||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.delete(`${this.baseUrl}/c/restful/maps/${mapId}/labels/${labelId}`)
|
.delete(`${this.baseUrl}/api/restful/maps/${mapId}/labels/${labelId}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
success();
|
success();
|
||||||
})
|
})
|
||||||
@ -640,7 +691,7 @@ export default class RestClient implements Client {
|
|||||||
reject: (error: ErrorInfo) => void,
|
reject: (error: ErrorInfo) => void,
|
||||||
) => {
|
) => {
|
||||||
this.axios
|
this.axios
|
||||||
.post(`${this.baseUrl}/service/oauth2/googlecallback?code=${code}`, {
|
.post(`${this.baseUrl}/api/restful/oauth2/googlecallback?code=${code}`, {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@ -661,7 +712,7 @@ export default class RestClient implements Client {
|
|||||||
confirmAccountSync(email: string, code: string): Promise<void> {
|
confirmAccountSync(email: string, code: string): Promise<void> {
|
||||||
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
const handler = (success: () => void, reject: (error: ErrorInfo) => void) => {
|
||||||
this.axios
|
this.axios
|
||||||
.put(`${this.baseUrl}/service/oauth2/confirmaccountsync?email=${email}&code=${code}`, {
|
.put(`${this.baseUrl}/api/restful/oauth2/confirmaccountsync?email=${email}&code=${code}`, {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { FormattedMessage, useIntl } from 'react-intl';
|
import { FormattedMessage, useIntl } from 'react-intl';
|
||||||
import { Link as RouterLink } from 'react-router-dom';
|
import { Link as RouterLink, useNavigate } from 'react-router-dom';
|
||||||
import Header from '../layout/header';
|
import Header from '../layout/header';
|
||||||
import Footer from '../layout/footer';
|
import Footer from '../layout/footer';
|
||||||
import SubmitButton from '../form/submit-button';
|
import SubmitButton from '../form/submit-button';
|
||||||
@ -15,6 +15,17 @@ import Separator from '../common/separator';
|
|||||||
import GoogleButton from '../common/google-button';
|
import GoogleButton from '../common/google-button';
|
||||||
import AppConfig from '../../classes/app-config';
|
import AppConfig from '../../classes/app-config';
|
||||||
import CSRFInput from '../common/csrf-input';
|
import CSRFInput from '../common/csrf-input';
|
||||||
|
import { useMutation } from 'react-query';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import Client, { ErrorInfo } from '../../classes/client';
|
||||||
|
import { activeInstance } from '../../redux/clientSlice';
|
||||||
|
|
||||||
|
export type Model = {
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultModel: Model = { email: '', password: '' };
|
||||||
|
|
||||||
const LoginError = () => {
|
const LoginError = () => {
|
||||||
// @Todo: This must be reviewed to be based on navigation state.
|
// @Todo: This must be reviewed to be based on navigation state.
|
||||||
@ -44,6 +55,9 @@ const LoginError = () => {
|
|||||||
|
|
||||||
const LoginPage = (): React.ReactElement => {
|
const LoginPage = (): React.ReactElement => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
const [model, setModel] = useState<Model>(defaultModel);
|
||||||
|
const client: Client = useSelector(activeInstance);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = intl.formatMessage({
|
document.title = intl.formatMessage({
|
||||||
@ -53,6 +67,29 @@ const LoginPage = (): React.ReactElement => {
|
|||||||
ReactGA.send({ hitType: 'pageview', page: window.location.pathname, title: 'Login' });
|
ReactGA.send({ hitType: 'pageview', page: window.location.pathname, title: 'Login' });
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const mutation = useMutation<void, ErrorInfo, Model>(
|
||||||
|
(model: Model) => client.login({ ...model }),
|
||||||
|
{
|
||||||
|
onSuccess: () => navigate('/c/maps/'),
|
||||||
|
onError: (error) => {
|
||||||
|
console.log(error);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleOnSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
||||||
|
mutation.mutate(model);
|
||||||
|
event.preventDefault();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const name = event.target.name;
|
||||||
|
const value = event.target.value;
|
||||||
|
setModel({ ...model, [name as keyof Model]: value });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Header type="only-signup" />
|
<Header type="only-signup" />
|
||||||
@ -69,10 +106,11 @@ const LoginPage = (): React.ReactElement => {
|
|||||||
<LoginError />
|
<LoginError />
|
||||||
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<form action="/c/perform-login" method="POST">
|
<form onSubmit={handleOnSubmit}>
|
||||||
<CSRFInput />
|
<CSRFInput />
|
||||||
<Input
|
<Input
|
||||||
name="username"
|
onChange={handleOnChange}
|
||||||
|
name="email"
|
||||||
type="email"
|
type="email"
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
id: 'login.email',
|
id: 'login.email',
|
||||||
@ -82,6 +120,7 @@ const LoginPage = (): React.ReactElement => {
|
|||||||
autoComplete="email"
|
autoComplete="email"
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
|
onChange={handleOnChange}
|
||||||
name="password"
|
name="password"
|
||||||
type="password"
|
type="password"
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
@ -91,12 +130,6 @@ const LoginPage = (): React.ReactElement => {
|
|||||||
required
|
required
|
||||||
autoComplete="current-password"
|
autoComplete="current-password"
|
||||||
/>
|
/>
|
||||||
<div>
|
|
||||||
<input name="remember-me" id="remember-me" type="checkbox" />
|
|
||||||
<label htmlFor="remember-me">
|
|
||||||
<FormattedMessage id="login.remberme" defaultMessage="Remember me" />
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<SubmitButton
|
<SubmitButton
|
||||||
value={intl.formatMessage({
|
value={intl.formatMessage({
|
||||||
id: 'login.signin',
|
id: 'login.signin',
|
||||||
|
@ -41,9 +41,9 @@ const RegistrationForm = () => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const Client: Client = useSelector(activeInstance);
|
const client: Client = useSelector(activeInstance);
|
||||||
const mutation = useMutation<void, ErrorInfo, Model>(
|
const mutation = useMutation<void, ErrorInfo, Model>(
|
||||||
(model: Model) => Client.registerNewUser({ ...model }),
|
(model: Model) => client.registerNewUser({ ...model }),
|
||||||
{
|
{
|
||||||
onSuccess: () => navigate('/c/registration-success'),
|
onSuccess: () => navigate('/c/registration-success'),
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
|
@ -10,6 +10,18 @@ module.exports = merge(common, {
|
|||||||
devServer: {
|
devServer: {
|
||||||
port: 3000,
|
port: 3000,
|
||||||
hot: true,
|
hot: true,
|
||||||
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: {
|
||||||
|
host: "0.0.0.0",
|
||||||
|
protocol: 'http:',
|
||||||
|
port: 8080
|
||||||
|
},
|
||||||
|
pathRewrite: {
|
||||||
|
'^/api': ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
historyApiFallback: {
|
historyApiFallback: {
|
||||||
rewrites: [{ from: /^\/c\//, to: '/index.html' }],
|
rewrites: [{ from: /^\/c\//, to: '/index.html' }],
|
||||||
},
|
},
|
||||||
@ -19,6 +31,7 @@ module.exports = merge(common, {
|
|||||||
template: path.join(__dirname, 'public/index.html'),
|
template: path.join(__dirname, 'public/index.html'),
|
||||||
templateParameters: {
|
templateParameters: {
|
||||||
PUBLIC_URL: process.env.PUBLIC_URL ? process.env.PUBLIC_URL : 'http://localhost:3000',
|
PUBLIC_URL: process.env.PUBLIC_URL ? process.env.PUBLIC_URL : 'http://localhost:3000',
|
||||||
|
CLIENT_TYPE: process.env.CLIENT_TYPE ? process.env.CLIENT_TYPE : 'mock'
|
||||||
},
|
},
|
||||||
base: process.env.PUBLIC_URL ? process.env.PUBLIC_URL : 'http://localhost:3000',
|
base: process.env.PUBLIC_URL ? process.env.PUBLIC_URL : 'http://localhost:3000',
|
||||||
}),
|
}),
|
||||||
|
Loading…
Reference in New Issue
Block a user