Page MenuHomePhabricator

D7867.id26664.diff
No OneTemporary

D7867.id26664.diff

diff --git a/keyserver/src/endpoints.js b/keyserver/src/endpoints.js
--- a/keyserver/src/endpoints.js
+++ b/keyserver/src/endpoints.js
@@ -38,7 +38,10 @@
reportMultiCreationResponder,
errorReportFetchInfosResponder,
} from './responders/report-responders.js';
-import { userSearchResponder } from './responders/search-responders.js';
+import {
+ userSearchResponder,
+ exactUserSearchResponder,
+} from './responders/search-responders.js';
import { siweNonceResponder } from './responders/siwe-nonce-responders.js';
import {
threadDeletionResponder,
@@ -133,6 +136,10 @@
responder: uploadDeletionResponder,
requiredPolicies: baseLegalPolicies,
},
+ exact_search_user: {
+ responder: exactUserSearchResponder,
+ requiredPolicies: [],
+ },
fetch_entries: {
responder: entryFetchResponder,
requiredPolicies: baseLegalPolicies,
diff --git a/keyserver/src/responders/search-responders.js b/keyserver/src/responders/search-responders.js
--- a/keyserver/src/responders/search-responders.js
+++ b/keyserver/src/responders/search-responders.js
@@ -5,11 +5,13 @@
import type {
UserSearchRequest,
UserSearchResult,
+ ExactUserSearchRequest,
+ ExactUserSearchResult,
} from 'lib/types/search-types.js';
import { globalAccountUserInfoValidator } from 'lib/types/user-types.js';
import { tShape } from 'lib/utils/validation-utils.js';
-import { searchForUsers } from '../search/users.js';
+import { searchForUsers, searchForUser } from '../search/users.js';
import type { Viewer } from '../session/viewer.js';
import { validateInput, validateOutput } from '../utils/validation-utils.js';
@@ -40,4 +42,30 @@
);
}
-export { userSearchResponder };
+const exactUserSearchRequestInputValidator = tShape<ExactUserSearchRequest>({
+ username: t.String,
+});
+
+const exactUserSearchResultValidator = tShape<ExactUserSearchResult>({
+ userInfo: t.maybe(globalAccountUserInfoValidator),
+});
+
+async function exactUserSearchResponder(
+ viewer: Viewer,
+ input: mixed,
+): Promise<ExactUserSearchResult> {
+ const request = await validateInput(
+ viewer,
+ exactUserSearchRequestInputValidator,
+ input,
+ );
+ const searchResult = await searchForUser(request.username);
+ const result = { userInfo: searchResult };
+ return validateOutput(
+ viewer.platformDetails,
+ exactUserSearchResultValidator,
+ result,
+ );
+}
+
+export { userSearchResponder, exactUserSearchResponder };
diff --git a/keyserver/src/search/users.js b/keyserver/src/search/users.js
--- a/keyserver/src/search/users.js
+++ b/keyserver/src/search/users.js
@@ -27,4 +27,21 @@
return userInfos;
}
-export { searchForUsers };
+async function searchForUser(
+ usernameQuery: string,
+): Promise<?GlobalAccountUserInfo> {
+ const query = SQL`
+ SELECT id, username
+ FROM users
+ WHERE LOWER(username) = LOWER(${usernameQuery})
+ `;
+ const [result] = await dbQuery(query);
+
+ if (result.length === 0) {
+ return null;
+ }
+ const { id, username } = result[0];
+ return { id, username };
+}
+
+export { searchForUsers, searchForUser };
diff --git a/lib/actions/user-actions.js b/lib/actions/user-actions.js
--- a/lib/actions/user-actions.js
+++ b/lib/actions/user-actions.js
@@ -15,7 +15,10 @@
UpdateUserAvatarResponse,
} from '../types/avatar-types.js';
import type { GetSessionPublicKeysArgs } from '../types/request-types.js';
-import type { UserSearchResult } from '../types/search-types.js';
+import type {
+ UserSearchResult,
+ ExactUserSearchResult,
+} from '../types/search-types.js';
import type {
SessionPublicKeys,
PreRequestUserState,
@@ -191,6 +194,24 @@
};
};
+const exactSearchUserActionTypes = Object.freeze({
+ started: 'EXACT_SEARCH_USER_STARTED',
+ success: 'EXACT_SEARCH_USER_SUCCESS',
+ failed: 'EXACT_SEARCH_USER_FAILED',
+});
+const exactSearchUser =
+ (
+ callServerEndpoint: CallServerEndpoint,
+ ): ((username: string) => Promise<ExactUserSearchResult>) =>
+ async username => {
+ const response = await callServerEndpoint('exact_search_user', {
+ username,
+ });
+ return {
+ userInfo: response.userInfo,
+ };
+ };
+
const updateSubscriptionActionTypes = Object.freeze({
started: 'UPDATE_SUBSCRIPTION_STARTED',
success: 'UPDATE_SUBSCRIPTION_SUCCESS',
@@ -282,6 +303,8 @@
registerActionTypes,
searchUsers,
searchUsersActionTypes,
+ exactSearchUser,
+ exactSearchUserActionTypes,
setUserSettings,
setUserSettingsActionTypes,
updateSubscription,
diff --git a/lib/types/endpoints.js b/lib/types/endpoints.js
--- a/lib/types/endpoints.js
+++ b/lib/types/endpoints.js
@@ -58,6 +58,7 @@
DELETE_ENTRY: 'delete_entry',
DELETE_THREAD: 'delete_thread',
DELETE_UPLOAD: 'delete_upload',
+ EXACT_SEARCH_USER: 'exact_search_user',
FETCH_ENTRIES: 'fetch_entries',
FETCH_ENTRY_REVISIONS: 'fetch_entry_revisions',
FETCH_ERROR_REPORT_INFOS: 'fetch_error_report_infos',
diff --git a/lib/types/redux-types.js b/lib/types/redux-types.js
--- a/lib/types/redux-types.js
+++ b/lib/types/redux-types.js
@@ -74,7 +74,10 @@
ReportStore,
} from './report-types.js';
import type { ProcessServerRequestsPayload } from './request-types.js';
-import type { UserSearchResult } from './search-types.js';
+import type {
+ UserSearchResult,
+ ExactUserSearchResult,
+} from './search-types.js';
import type { SetSessionPayload } from './session-types.js';
import type {
ConnectionInfo,
@@ -583,6 +586,22 @@
+payload: UserSearchResult,
+loadingInfo: LoadingInfo,
}
+ | {
+ +type: 'EXACT_SEARCH_USER_STARTED',
+ +payload?: void,
+ +loadingInfo: LoadingInfo,
+ }
+ | {
+ +type: 'EXACT_SEARCH_USER_FAILED',
+ +error: true,
+ +payload: Error,
+ +loadingInfo: LoadingInfo,
+ }
+ | {
+ +type: 'EXACT_SEARCH_USER_SUCCESS',
+ +payload: ExactUserSearchResult,
+ +loadingInfo: LoadingInfo,
+ }
| {
+type: 'UPDATE_DRAFT',
+payload: {
diff --git a/lib/types/search-types.js b/lib/types/search-types.js
--- a/lib/types/search-types.js
+++ b/lib/types/search-types.js
@@ -3,8 +3,15 @@
import type { GlobalAccountUserInfo } from './user-types.js';
export type UserSearchRequest = {
- prefix?: string,
+ +prefix?: string,
};
export type UserSearchResult = {
- userInfos: $ReadOnlyArray<GlobalAccountUserInfo>,
+ +userInfos: $ReadOnlyArray<GlobalAccountUserInfo>,
+};
+
+export type ExactUserSearchRequest = {
+ +username: string,
+};
+export type ExactUserSearchResult = {
+ +userInfo: ?GlobalAccountUserInfo,
};
diff --git a/native/account/registration/connect-ethereum.react.js b/native/account/registration/connect-ethereum.react.js
--- a/native/account/registration/connect-ethereum.react.js
+++ b/native/account/registration/connect-ethereum.react.js
@@ -3,6 +3,16 @@
import * as React from 'react';
import { Text, View } from 'react-native';
+import {
+ exactSearchUser,
+ exactSearchUserActionTypes,
+} from 'lib/actions/user-actions.js';
+import type { SIWEResult } from 'lib/types/siwe-types.js';
+import {
+ useServerCall,
+ useDispatchActionPromise,
+} from 'lib/utils/action-utils.js';
+
import RegistrationButtonContainer from './registration-button-container.react.js';
import RegistrationButton from './registration-button.react.js';
import RegistrationContainer from './registration-container.react.js';
@@ -94,8 +104,27 @@
[panelState],
);
- const onSkip = React.useCallback(() => {}, []);
- const onSuccessfulWalletSignature = React.useCallback(() => {}, []);
+ const onSkip = React.useCallback(() => {
+ // show username selection screen
+ }, []);
+
+ const exactSearchUserCall = useServerCall(exactSearchUser);
+ const dispatchActionPromise = useDispatchActionPromise();
+
+ const onSuccessfulWalletSignature = React.useCallback(
+ async (result: SIWEResult) => {
+ const searchPromise = exactSearchUserCall(result.address);
+ dispatchActionPromise(exactSearchUserActionTypes, searchPromise);
+ const { userInfo } = await searchPromise;
+
+ if (userInfo) {
+ // show duplicate account screen
+ } else {
+ // show avatar selection screen
+ }
+ },
+ [exactSearchUserCall, dispatchActionPromise],
+ );
let siwePanel;
if (panelState !== 'closed') {

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 26, 11:06 PM (20 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2586798
Default Alt Text
D7867.id26664.diff (8 KB)

Event Timeline