forked from Ivasoft/mattermost-mobile
MM_35115: Login screen - email - login api call [IN PROGRESS]
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
"extends": [
|
||||
"plugin:mattermost/react",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:react-hooks/recommended"
|
||||
],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": [
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {ClientOptions} from '@typings/api/client4';
|
||||
import urlParse from 'url-parse';
|
||||
|
||||
import {Analytics, create} from '@init/analytics';
|
||||
@@ -12,7 +13,7 @@ import * as ClientConstants from './constants';
|
||||
import ClientError from './error';
|
||||
|
||||
export default class ClientBase {
|
||||
analitics: Analytics|undefined;
|
||||
analytics: Analytics|undefined;
|
||||
clusterId = '';
|
||||
csrf = '';
|
||||
defaultHeaders: {[x: string]: string} = {};
|
||||
@@ -127,7 +128,7 @@ export default class ClientBase {
|
||||
|
||||
setUrl(url: string) {
|
||||
this.url = url.replace(/\/+$/, '');
|
||||
this.analitics = create(this.url);
|
||||
this.analytics = create(this.url);
|
||||
}
|
||||
|
||||
// Routes
|
||||
|
||||
@@ -47,7 +47,7 @@ const ErrorText = ({error, testID, textStyle, theme}: ErrorProps) => {
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
return {
|
||||
errorLabel: {
|
||||
color: (theme.errorTextColor || '#DA4A4A'),
|
||||
color: (theme?.errorTextColor || '#DA4A4A'),
|
||||
marginTop: 15,
|
||||
marginBottom: 15,
|
||||
fontSize: 12,
|
||||
|
||||
@@ -7,10 +7,12 @@ import DatabaseConnectionException from '@database/exceptions/database_connectio
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {Q} from '@nozbe/watermelondb';
|
||||
import {Client4Error} from '@typings/api/client4';
|
||||
import Global from '@typings/database/global';
|
||||
|
||||
const HTTP_UNAUTHORIZED = 401;
|
||||
|
||||
//fixme: this file needs to be finalized
|
||||
//todo: retrieve deviceToken from default database - Global entity
|
||||
|
||||
export const logout = async (skipServerLogout = false) => {
|
||||
return async () => {
|
||||
@@ -42,3 +44,41 @@ export const forceLogoutIfNecessary = async (err: Client4Error) => {
|
||||
logout(false);
|
||||
}
|
||||
};
|
||||
|
||||
type LoginArgs = {loginId: string, password: string, mfaToken?: string, ldapOnly?: boolean}
|
||||
export const login = async ({loginId, password, mfaToken, ldapOnly = false}: LoginArgs) => {
|
||||
const database = await DatabaseManager.getDefaultDatabase();
|
||||
|
||||
if (!database) {
|
||||
throw new DatabaseConnectionException('DatabaseManager.getActiveServerDatabase returned undefined');
|
||||
}
|
||||
|
||||
let deviceToken;
|
||||
let user;
|
||||
|
||||
try {
|
||||
const tokens = await database.collections.get(MM_TABLES.DEFAULT.GLOBAL).query(Q.where('name', 'deviceToken')).fetch() as Global[];
|
||||
|
||||
console.log('called login api method with ', loginId, password);
|
||||
deviceToken = tokens?.[0]?.value ?? '';
|
||||
user = await Client4.login(loginId, password, mfaToken, deviceToken, ldapOnly);
|
||||
console.log('user =>> ', user);
|
||||
|
||||
//todo : setCSRFFromCookie
|
||||
// await setCSRFFromCookie(Client4.getUrl());
|
||||
} catch (error) {
|
||||
return {error};
|
||||
}
|
||||
|
||||
//todo : loadMe
|
||||
// const result = await dispatch(loadMe(user));
|
||||
|
||||
// if (!result.error) {
|
||||
// //todo: completeLogin
|
||||
// // dispatch(completeLogin(user, deviceToken));
|
||||
// }
|
||||
// return user;
|
||||
// return result;
|
||||
|
||||
return user;
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {login} from '@requests/remote/user';
|
||||
import React, {useCallback, useEffect, useRef, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Dimensions,
|
||||
Image,
|
||||
InteractionManager,
|
||||
Keyboard,
|
||||
@@ -53,14 +53,22 @@ const Login: NavigationFunctionComponent = ({config, license, theme}: LoginProps
|
||||
const managedConfig = useManagedConfig();
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [error, setError] = useState<ClientErrorWithIntl | string | undefined | null>();
|
||||
const [loginId, setLoginId] = useState<string>('');
|
||||
const [password, setPassword] = useState<string>('');
|
||||
|
||||
//fixme: remove hardcoded value for loginId and password
|
||||
const [loginId, setLoginId] = useState<string>('avinash.lingaloo@mattermost.com');
|
||||
const [password, setPassword] = useState<string>('AluminiumZ545*');
|
||||
|
||||
//fixme: is this necessary ?
|
||||
// useEffect for orientation change
|
||||
useEffect(() => {
|
||||
Dimensions.addEventListener('change', handleOrientationDidChange);
|
||||
return () => Dimensions.removeEventListener('change', handleOrientationDidChange);
|
||||
}, []);
|
||||
// useEffect(() => {
|
||||
// const handleOrientationDidChange = () => {
|
||||
// if (this.scroll.current) {
|
||||
// this.scroll.current.scrollTo({x: 0, y: 0, animated: true});
|
||||
// }
|
||||
// };
|
||||
// Dimensions.addEventListener('change', handleOrientationDidChange);
|
||||
// return () => Dimensions.removeEventListener('change', handleOrientationDidChange);
|
||||
// }, []);
|
||||
|
||||
// useEffect to set userName for EMM
|
||||
useEffect(() => {
|
||||
@@ -74,14 +82,10 @@ const Login: NavigationFunctionComponent = ({config, license, theme}: LoginProps
|
||||
setEmmUsernameIfAvailable();
|
||||
}, []);
|
||||
|
||||
const handleOrientationDidChange = () => {
|
||||
if (this.scroll.current) {
|
||||
this.scroll.current.scrollTo({x: 0, y: 0, animated: true});
|
||||
}
|
||||
};
|
||||
const preSignIn = preventDoubleTap(() => {
|
||||
const preSignIn = preventDoubleTap(async () => {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
|
||||
Keyboard.dismiss();
|
||||
InteractionManager.runAfterInteractions(async () => {
|
||||
if (!loginId) {
|
||||
@@ -111,43 +115,35 @@ const Login: NavigationFunctionComponent = ({config, license, theme}: LoginProps
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
setError(
|
||||
intl.formatMessage(
|
||||
{
|
||||
id: msgId,
|
||||
defaultMessage: '',
|
||||
},
|
||||
{
|
||||
ldapUsername: config.LdapLoginFieldName || ldapUsername,
|
||||
},
|
||||
),
|
||||
);
|
||||
setError(intl.formatMessage(
|
||||
{
|
||||
id: msgId,
|
||||
defaultMessage: '',
|
||||
},
|
||||
{
|
||||
ldapUsername: config.LdapLoginFieldName || ldapUsername,
|
||||
},
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!password) {
|
||||
setIsLoading(false);
|
||||
setError(
|
||||
intl.formatMessage(
|
||||
{
|
||||
id: t('login.noPassword'),
|
||||
defaultMessage: 'Please enter your password',
|
||||
},
|
||||
),
|
||||
);
|
||||
setError(intl.formatMessage({
|
||||
id: t('login.noPassword'),
|
||||
defaultMessage: 'Please enter your password',
|
||||
}));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
signIn();
|
||||
});
|
||||
});
|
||||
|
||||
const signIn = async () => {
|
||||
if (isLoading) {
|
||||
const result = await login(loginId.toLowerCase(), password);
|
||||
if (checkLoginResponse(result)) {
|
||||
goToChannel();
|
||||
}
|
||||
const result = await login({loginId: loginId.toLowerCase(), password});
|
||||
if (checkLoginResponse(result)) {
|
||||
goToChannel();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -160,10 +156,9 @@ const Login: NavigationFunctionComponent = ({config, license, theme}: LoginProps
|
||||
scheduleExpiredNotification(intl);
|
||||
};
|
||||
|
||||
const checkLoginResponse = (data) => {
|
||||
const checkLoginResponse = (data: any) => {
|
||||
if (MFA_EXPECTED_ERRORS.includes(data?.error?.server_error_id)) { // eslint-disable-line camelcase
|
||||
goToMfa();
|
||||
|
||||
setIsLoading(false);
|
||||
return false;
|
||||
}
|
||||
@@ -184,11 +179,11 @@ const Login: NavigationFunctionComponent = ({config, license, theme}: LoginProps
|
||||
goToScreen(screen, title, {goToChannel, loginId, password});
|
||||
};
|
||||
|
||||
const getLoginErrorMessage = (loginError) => {
|
||||
const getLoginErrorMessage = (loginError: any) => {
|
||||
return (getServerErrorForLogin(loginError) || loginError);
|
||||
};
|
||||
|
||||
const getServerErrorForLogin = (serverError) => {
|
||||
const getServerErrorForLogin = (serverError: any) => {
|
||||
if (!serverError) {
|
||||
return null;
|
||||
}
|
||||
@@ -338,14 +333,14 @@ const Login: NavigationFunctionComponent = ({config, license, theme}: LoginProps
|
||||
source={require('@assets/images/logo.png')}
|
||||
style={{height: 72, resizeMode: 'contain'}}
|
||||
/>
|
||||
<View testID='login.screen'>
|
||||
<Text style={GlobalStyles.header}>{config.SiteName}</Text>
|
||||
{config?.SiteName && (<View testID='login.screen'>
|
||||
<Text style={GlobalStyles.header}>{config?.SiteName}</Text>
|
||||
<FormattedText
|
||||
style={GlobalStyles.subheader}
|
||||
id='web.root.signup_info'
|
||||
defaultMessage='All team communication in one place, searchable and accessible anywhere'
|
||||
/>
|
||||
</View>
|
||||
</View>)}
|
||||
{error && (
|
||||
<ErrorText
|
||||
testID='login.error.text'
|
||||
@@ -368,6 +363,7 @@ const Login: NavigationFunctionComponent = ({config, license, theme}: LoginProps
|
||||
returnKeyType='next'
|
||||
style={GlobalStyles.inputBox}
|
||||
underlineColorAndroid='transparent'
|
||||
value={loginId} //to remove
|
||||
/>
|
||||
<TextInput
|
||||
testID='login.password.input'
|
||||
@@ -386,6 +382,7 @@ const Login: NavigationFunctionComponent = ({config, license, theme}: LoginProps
|
||||
returnKeyType='go'
|
||||
secureTextEntry={true}
|
||||
underlineColorAndroid='transparent'
|
||||
value={password} //to remove
|
||||
/>
|
||||
{getProceed()}
|
||||
{(config.EnableSignInWithEmail === 'true' || config.EnableSignInWithUsername === 'true') && (
|
||||
|
||||
@@ -37,7 +37,9 @@ const Server: NavigationFunctionComponent = ({theme}: ServerProps) => {
|
||||
const input = useRef<TextInput>(null);
|
||||
const [connecting, setConnecting] = useState(false);
|
||||
const [error, setError] = useState<ClientErrorWithIntl|string|undefined>();
|
||||
const [url, setUrl] = useState<string>('');
|
||||
|
||||
//fixme: remove hardcoded url
|
||||
const [url, setUrl] = useState<string>('https://rc.test.mattermost.com');
|
||||
const styles = getStyleSheet(theme);
|
||||
const {formatMessage} = intl;
|
||||
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
"eslint-plugin-jest": "24.3.5",
|
||||
"eslint-plugin-mattermost": "github:mattermost/eslint-plugin-mattermost#070ce792d105482ffb2b27cfc0b7e78b3d20acee",
|
||||
"eslint-plugin-react": "7.23.2",
|
||||
"eslint-plugin-react-hooks": "4.2.0",
|
||||
"husky": "6.0.0",
|
||||
"isomorphic-fetch": "3.0.0",
|
||||
"jest": "26.6.3",
|
||||
|
||||
14
types/api/client4.d.ts
vendored
14
types/api/client4.d.ts
vendored
@@ -1,30 +1,30 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
declare type logLevel = 'ERROR' | 'WARNING' | 'INFO';
|
||||
declare type GenericClientResponse = {
|
||||
export type logLevel = 'ERROR' | 'WARNING' | 'INFO';
|
||||
export type GenericClientResponse = {
|
||||
response: any;
|
||||
headers: Map<string, string>;
|
||||
data: any;
|
||||
};
|
||||
declare type ErrorOffline = {
|
||||
export type ErrorOffline = {
|
||||
message: string;
|
||||
url: string;
|
||||
};
|
||||
declare type ErrorInvalidResponse = {
|
||||
export type ErrorInvalidResponse = {
|
||||
intl: {
|
||||
id: string;
|
||||
defaultMessage: string;
|
||||
};
|
||||
};
|
||||
declare type ErrorApi = {
|
||||
export type ErrorApi = {
|
||||
message: string;
|
||||
server_error_id: string;
|
||||
status_code: number;
|
||||
url: string;
|
||||
};
|
||||
declare type Client4Error = ErrorOffline | ErrorInvalidResponse | ErrorApi;
|
||||
declare type ClientOptions = {
|
||||
export type Client4Error = ErrorOffline | ErrorInvalidResponse | ErrorApi;
|
||||
export type ClientOptions = {
|
||||
headers?: {
|
||||
[x: string]: string;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user