Skip to content

Commit a2e416e

Browse files
Implement anonymous login
1 parent 346f661 commit a2e416e

File tree

9 files changed

+115
-29
lines changed

9 files changed

+115
-29
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"ios": "react-native run-ios",
1717
"lint": "eslint .",
1818
"lint:fix": "eslint . --fix",
19+
"typecheck": "tsc --noEmit",
1920
"start": "react-native start",
2021
"test": "jest --passWithNoTests",
2122
"postinstall": "yarn run npm-license-crawler -onlyDirectDependencies -json licenses.json && patch-package",

src/api/opendtuapi.ts

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class OpenDtuApi {
6969
this.baseUrl = baseUrl;
7070
}
7171

72-
public setUserString(userString: string): void {
72+
public setUserString(userString: string | null): void {
7373
this.userString = userString;
7474
}
7575

@@ -142,7 +142,7 @@ class OpenDtuApi {
142142
this.onDisconnectedHandler = null;
143143
}
144144

145-
private async getSystemStatusFromUrl(
145+
public async getSystemStatusFromUrl(
146146
url: URL,
147147
): Promise<GetSystemStatusReturn> {
148148
// GET <url>/api/system/status
@@ -288,13 +288,15 @@ class OpenDtuApi {
288288
return;
289289
}
290290

291-
if (this.baseUrl && this.userString) {
291+
if (this.baseUrl) {
292292
const urlObject = new URL(this.baseUrl);
293293
const authString = this.getAuthString();
294294
const protocol = urlObject.protocol === 'https:' ? 'wss' : 'ws';
295295
const host = urlObject.host;
296296

297-
const url = `${protocol}://${authString}${host}/livedata`;
297+
const url = `${protocol}://${authString ?? ''}${host}/livedata`;
298+
299+
console.log(`Connecting websocket to ${url}`);
298300

299301
this.ws = new WebSocket(url);
300302

@@ -466,9 +468,13 @@ class OpenDtuApi {
466468
);
467469
}
468470

469-
private getAuthString(): string {
471+
private getAuthString(): string | null {
470472
let user = null;
471473

474+
if (!this.userString) {
475+
return null;
476+
}
477+
472478
try {
473479
user = JSON.parse(this.userString || '');
474480
} catch {
@@ -492,6 +498,10 @@ class OpenDtuApi {
492498
'GET',
493499
);
494500

501+
if (!res) {
502+
return null;
503+
}
504+
495505
if (res.status === 200) {
496506
return await res.json();
497507
}
@@ -506,6 +516,10 @@ class OpenDtuApi {
506516

507517
const res = await this.makeAuthenticatedRequest('/api/ntp/status', 'GET');
508518

519+
if (!res) {
520+
return null;
521+
}
522+
509523
if (res.status === 200) {
510524
return await res.json();
511525
}
@@ -520,6 +534,10 @@ class OpenDtuApi {
520534

521535
const res = await this.makeAuthenticatedRequest('/api/mqtt/status', 'GET');
522536

537+
if (!res) {
538+
return null;
539+
}
540+
523541
if (res.status === 200) {
524542
return await res.json();
525543
}
@@ -531,7 +549,7 @@ class OpenDtuApi {
531549
route: string,
532550
method: string,
533551
body: string | null = null,
534-
): Promise<Response> {
552+
): Promise<Response | null> {
535553
const authString = this.getAuthString();
536554

537555
const controller = new AbortController();
@@ -546,8 +564,8 @@ class OpenDtuApi {
546564
signal: controller.signal,
547565
headers: {
548566
'X-Requested-With': 'XMLHttpRequest',
549-
Authorization: 'Basic ' + authString,
550567
'Content-Type': 'application/json',
568+
...(authString ? { Authorization: 'Basic ' + authString } : {}),
551569
},
552570
};
553571

@@ -558,12 +576,16 @@ class OpenDtuApi {
558576
const url = `${authString}${this.baseUrl}${route}`;
559577

560578
console.log('makeAuthenticatedRequest', url, requestOptions);
561-
const res = await fetch(url, requestOptions);
562-
if (res.status === 200) {
579+
580+
try {
581+
const res = await fetch(url, requestOptions);
563582
clearTimeout(abortTimeout);
564-
}
565583

566-
return res;
584+
return res;
585+
} catch (error) {
586+
console.log('makeAuthenticatedRequest error', error);
587+
return null;
588+
}
567589
}
568590
}
569591

src/translations/translation-files

src/types/opendtu/state.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export type SetSystemStatusAction = PayloadAction<{
3232
}>;
3333

3434
export type SetSetupUserStringAction = PayloadAction<{
35-
userString: string;
35+
userString: string | null;
3636
}>;
3737

3838
export type SetSetupBaseUrlAction = PayloadAction<{

src/types/settings.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export type Index = number;
77
export interface OpenDTUConfig {
88
// Config to connect to OpenDTU. It will be possible to configure multiple
99
baseUrl: string;
10-
userString: string; // same as 'user' from webinterface localstorage
10+
userString: string | null; // same as 'user' from webinterface localstorage (null means no auth, so read-only)
1111
serialNumber: string | null; // null means never connected
1212
hostname: string | null; // null means never connected
1313
customName: string | null; // null means customName is not set

src/views/navigation/screens/SetupAddOpenDTUScreen.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const SetupAddOpenDTUScreen: FC<PropsWithNavigation> = ({ navigation }) => {
5959
try {
6060
url = new URL(ourAddress);
6161
} catch {
62-
setError('Invalid address');
62+
setError(t('setup.errors.invalidAddress'));
6363
return;
6464
}
6565

@@ -110,7 +110,7 @@ const SetupAddOpenDTUScreen: FC<PropsWithNavigation> = ({ navigation }) => {
110110
navigation.navigate('SetupAuthenticateOpenDTUInstanceScreen');
111111

112112
setLoading(false);
113-
}, [address, baseUrls, dispatch, navigation, openDtuApi]);
113+
}, [t, address, baseUrls, dispatch, navigation, openDtuApi]);
114114

115115
const valid = !!address;
116116

src/views/navigation/screens/SetupAuthenticateOpenDTUInstanceScreen.tsx

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Box } from 'react-native-flex-layout';
55
import { logger } from 'react-native-logs';
66
import {
77
Button,
8+
Divider,
89
HelperText,
910
TextInput,
1011
Title,
@@ -13,6 +14,8 @@ import {
1314

1415
import { setSetupUserString } from '@/slices/opendtu';
1516

17+
import { DeviceState } from '@/types/opendtu/state';
18+
1619
import StyledTextInput from '@/components/styled/StyledTextInput';
1720

1821
import { useApi } from '@/api/ApiHandler';
@@ -57,7 +60,7 @@ const SetupAuthenticateOpenDTUInstanceScreen: FC<PropsWithNavigation> = ({
5760
);
5861

5962
if (result === false) {
60-
setError('Invalid credentials');
63+
setError(t('setup.errors.invalidCredentials'));
6164
log.info('Invalid credentials');
6265
setLoading(false);
6366
return;
@@ -70,12 +73,40 @@ const SetupAuthenticateOpenDTUInstanceScreen: FC<PropsWithNavigation> = ({
7073

7174
return;
7275
} else {
73-
setError('Something went wrong! Please try again.');
76+
setError(t('setup.errors.genericError'));
7477
log.info('Something went wrong! Please try again.');
7578
}
7679

7780
setLoading(false);
78-
}, [address, username, password, openDtuApi, dispatch, navigation]);
81+
}, [t, address, username, password, openDtuApi, dispatch, navigation]);
82+
83+
const handleAnonymous = useCallback(async () => {
84+
if (!address) return;
85+
86+
setLoading(true);
87+
setError(null);
88+
89+
try {
90+
const result = await openDtuApi.getSystemStatusFromUrl(new URL(address));
91+
92+
if (result.deviceState !== DeviceState.Reachable) {
93+
setError('Invalid credentials');
94+
log.info('Invalid credentials');
95+
setLoading(false);
96+
return;
97+
}
98+
99+
dispatch(setSetupUserString({ userString: null }));
100+
navigation.navigate('SetupOpenDTUCompleteScreen');
101+
setLoading(false);
102+
103+
setLoading(false);
104+
} catch (e) {
105+
setError(t('setup.errors.genericError'));
106+
log.info('Error while connecting to OpenDTU instance', e);
107+
setLoading(false);
108+
}
109+
}, [address, openDtuApi, dispatch, navigation, t]);
79110

80111
return (
81112
<StyledSafeAreaView theme={theme} style={{ justifyContent: 'center' }}>
@@ -131,6 +162,15 @@ const SetupAuthenticateOpenDTUInstanceScreen: FC<PropsWithNavigation> = ({
131162
>
132163
{t('setup.login')}
133164
</Button>
165+
<Divider />
166+
<Button
167+
// anonymous button
168+
mode="text"
169+
onPress={handleAnonymous}
170+
disabled={loading || !previousStepValid}
171+
>
172+
{t('setup.anonymous')}
173+
</Button>
134174
</Box>
135175
</StyledSafeAreaView>
136176
);

src/views/navigation/screens/SetupOpenDTUCompleteScreen.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const SetupOpenDTUCompleteScreen: FC<PropsWithNavigation> = ({
2121
const setupConfig = useAppSelector(state => state.opendtu.setup);
2222

2323
const handleFinishSetup = useCallback(() => {
24-
if (!setupConfig.userString || !setupConfig.baseUrl) return;
24+
if (!setupConfig.baseUrl) return;
2525

2626
dispatch(
2727
addDtuConfig({

src/views/navigation/tabs/MainSettingsTab.tsx

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { NavigationProp, ParamListBase } from '@react-navigation/native';
22
import { useNavigation } from '@react-navigation/native';
33

44
import type { FC } from 'react';
5-
import { useCallback, useState } from 'react';
5+
import { useMemo, useCallback, useState } from 'react';
66
import { useTranslation } from 'react-i18next';
77
import { ScrollView } from 'react-native';
88
import { Box } from 'react-native-flex-layout';
@@ -11,6 +11,7 @@ import { Badge, List, useTheme } from 'react-native-paper';
1111
import ChangeLanguageModal from '@/components/modals/ChangeLanguageModal';
1212
import ChangeThemeModal from '@/components/modals/ChangeThemeModal';
1313

14+
import useDtuState from '@/hooks/useDtuState';
1415
import useHasNewAppVersion from '@/hooks/useHasNewAppVersion';
1516
import useIsConnected from '@/hooks/useIsConnected';
1617

@@ -39,6 +40,28 @@ const MainSettingsTab: FC = () => {
3940
usedForIndicatorOnly: true,
4041
});
4142

43+
const hasSystemInformation = !!useDtuState(state => !!state?.systemStatus);
44+
const hasNetworkInformation = !!useDtuState(state => !!state?.networkStatus);
45+
const hasNtpInformation = !!useDtuState(state => !!state?.ntpStatus);
46+
const hasMqttInformation = !!useDtuState(state => !!state?.mqttStatus);
47+
48+
const systemInformationDisabled = useMemo(
49+
() => !hasSystemInformation || !websocketConnected,
50+
[hasSystemInformation, websocketConnected],
51+
);
52+
const networkInformationDisabled = useMemo(
53+
() => !hasNetworkInformation || !websocketConnected,
54+
[hasNetworkInformation, websocketConnected],
55+
);
56+
const ntpInformationDisabled = useMemo(
57+
() => !hasNtpInformation || !websocketConnected,
58+
[hasNtpInformation, websocketConnected],
59+
);
60+
const mqttInformationDisabled = useMemo(
61+
() => !hasMqttInformation || !websocketConnected,
62+
[hasMqttInformation, websocketConnected],
63+
);
64+
4265
const handleAbout = useCallback(() => {
4366
navigation.navigate('AboutSettingsScreen');
4467
}, [navigation]);
@@ -74,32 +97,32 @@ const MainSettingsTab: FC = () => {
7497
description={t('opendtu.systemInformationDescription')}
7598
left={props => <List.Icon {...props} icon="information" />}
7699
onPress={handleAboutOpenDTU}
77-
disabled={!websocketConnected}
78-
style={{ opacity: websocketConnected ? 1 : 0.5 }}
100+
disabled={systemInformationDisabled}
101+
style={{ opacity: systemInformationDisabled ? 0.5 : 1 }}
79102
/>
80103
<List.Item
81104
title={t('opendtu.networkInformation')}
82105
description={t('opendtu.networkInformationDescription')}
83106
left={props => <List.Icon {...props} icon="wifi" />}
84107
onPress={handleNetworkInformation}
85-
disabled={!websocketConnected}
86-
style={{ opacity: websocketConnected ? 1 : 0.5 }}
108+
disabled={networkInformationDisabled}
109+
style={{ opacity: networkInformationDisabled ? 0.5 : 1 }}
87110
/>
88111
<List.Item
89112
title={t('opendtu.ntpInformation')}
90113
description={t('opendtu.ntpInformationDescription')}
91114
left={props => <List.Icon {...props} icon="clock" />}
92115
onPress={handleNtpInformation}
93-
disabled={!websocketConnected}
94-
style={{ opacity: websocketConnected ? 1 : 0.5 }}
116+
disabled={ntpInformationDisabled}
117+
style={{ opacity: ntpInformationDisabled ? 0.5 : 1 }}
95118
/>
96119
<List.Item
97120
title={t('opendtu.mqttInformation')}
98121
description={t('opendtu.mqttInformationDescription')}
99122
left={props => <List.Icon {...props} icon="broadcast" />}
100123
onPress={handleMqttInformation}
101-
disabled={!websocketConnected}
102-
style={{ opacity: websocketConnected ? 1 : 0.5 }}
124+
disabled={mqttInformationDisabled}
125+
style={{ opacity: mqttInformationDisabled ? 0.5 : 1 }}
103126
/>
104127
</List.Section>
105128
<List.Section>

0 commit comments

Comments
 (0)