From 8cd127a223c2c02a28b132309f6e7a1067d36cd3 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Thu, 15 Jul 2021 11:49:02 -0400 Subject: [PATCH] [Gekidou] Typings & PostMetadata structure (#5542) * Typings & PostMetadata structure * comment out unused code * Remove duplicate interface * Fix getPreferenceAsBool defaultValue --- .../mattermost/rnbeta/MainApplication.java | 93 +--- app/actions/local/timezone.ts | 3 +- app/actions/remote/general.ts | 66 ++- app/actions/remote/preference.ts | 40 ++ app/actions/remote/push_notification.ts | 3 +- app/actions/remote/systems.ts | 55 +- app/actions/remote/team.ts | 57 ++ app/actions/remote/user.ts | 99 ++-- app/client/rest/preferences.ts | 2 +- app/constants/preferences.ts | 3 +- app/database/manager/__mocks__/index.ts | 67 +-- app/database/manager/index.ts | 34 +- app/database/models/app/global.ts | 2 +- app/database/models/app/index.ts | 6 +- app/database/models/app/info.ts | 2 +- app/database/models/app/servers.ts | 2 +- app/database/models/server/channel.ts | 43 +- app/database/models/server/channel_info.ts | 7 +- .../models/server/channel_membership.ts | 15 +- app/database/models/server/custom_emoji.ts | 2 +- app/database/models/server/draft.ts | 2 +- app/database/models/server/file.ts | 7 +- app/database/models/server/group.ts | 15 +- .../models/server/group_membership.ts | 15 +- .../models/server/groups_in_channel.ts | 11 +- app/database/models/server/groups_in_team.ts | 11 +- app/database/models/server/index.ts | 52 +- app/database/models/server/my_channel.ts | 7 +- .../models/server/my_channel_settings.ts | 8 +- app/database/models/server/my_team.ts | 7 +- app/database/models/server/post.ts | 32 +- app/database/models/server/post_metadata.ts | 12 +- .../models/server/posts_in_channel.ts | 7 +- app/database/models/server/posts_in_thread.ts | 7 +- app/database/models/server/preference.ts | 7 +- app/database/models/server/reaction.ts | 11 +- app/database/models/server/role.ts | 2 +- app/database/models/server/slash_command.ts | 7 +- app/database/models/server/system.ts | 2 +- app/database/models/server/team.ts | 31 +- .../models/server/team_channel_history.ts | 6 +- app/database/models/server/team_membership.ts | 15 +- .../models/server/team_search_history.ts | 7 +- .../models/server/terms_of_service.ts | 2 +- app/database/models/server/user.ts | 36 +- .../app_data_operator/comparator/index.ts | 14 +- .../operator/app_data_operator/index.test.ts | 50 +- .../operator/app_data_operator/index.ts | 50 +- .../app_data_operator/transformers/index.ts | 59 +- .../app_data_operator/transformers/test.ts | 32 +- .../operator/base_data_operator/index.ts | 7 +- .../server_data_operator/comparators/index.ts | 117 ++-- .../handlers/channel.test.ts | 42 +- .../server_data_operator/handlers/channel.ts | 64 +-- .../handlers/group.test.ts | 6 +- .../server_data_operator/handlers/group.ts | 64 +-- .../handlers/index.test.ts | 24 +- .../server_data_operator/handlers/index.ts | 41 +- .../handlers/post.test.ts | 23 +- .../server_data_operator/handlers/post.ts | 176 +++--- .../handlers/team.test.ts | 12 +- .../server_data_operator/handlers/team.ts | 106 ++-- .../handlers/user.test.ts | 22 +- .../server_data_operator/handlers/user.ts | 74 ++- .../transformers/channel.test.ts | 46 +- .../transformers/channel.ts | 71 ++- .../transformers/general.test.ts | 8 +- .../transformers/general.ts | 63 +-- .../transformers/group.test.ts | 12 +- .../transformers/group.ts | 65 ++- .../transformers/post.test.ts | 40 +- .../server_data_operator/transformers/post.ts | 96 ++-- .../transformers/team.test.ts | 16 +- .../server_data_operator/transformers/team.ts | 94 ++-- .../transformers/user.test.ts | 25 +- .../server_data_operator/transformers/user.ts | 63 +-- app/database/operator/utils/general.ts | 28 +- app/database/operator/utils/post.ts | 12 +- app/database/operator/utils/reaction.ts | 9 +- app/database/operator/utils/test.ts | 28 +- .../server/table_schemas/post_metadata.ts | 1 - app/database/schema/server/test.ts | 2 - app/helpers/api/preference.ts | 26 + app/helpers/api/team.ts | 62 +++ app/init/global_event_handler.ts | 2 +- app/queries/servers/preference.ts | 15 + app/queries/servers/system.ts | 44 +- app/queries/servers/team.ts | 23 + app/screens/channel/index.tsx | 2 +- app/screens/mfa/index.tsx | 6 +- app/screens/server/index.tsx | 3 +- babel.config.js | 1 + tsconfig.json | 1 + types/api/channels.d.ts | 11 +- types/api/emojis.d.ts | 12 +- types/api/files.d.ts | 5 +- types/api/groups.d.ts | 8 +- types/api/posts.d.ts | 43 +- types/api/reactions.d.ts | 1 + types/api/roles.d.ts | 14 +- types/api/slash_command.d.ts | 22 + types/api/teams.d.ts | 4 +- types/api/users.d.ts | 13 +- types/database/database.d.ts | 505 ++---------------- types/database/index.d.ts | 60 --- types/database/models/app/global.d.ts | 2 +- types/database/models/app/info.d.ts | 2 +- types/database/models/app/servers.d.ts | 2 +- types/database/models/servers/channel.d.ts | 33 +- .../database/models/servers/channel_info.d.ts | 6 +- .../models/servers/channel_membership.d.ts | 11 +- types/database/models/servers/config.ts | 170 ------ .../database/models/servers/custom_emoji.d.ts | 2 +- types/database/models/servers/draft.d.ts | 2 +- types/database/models/servers/file.d.ts | 6 +- types/database/models/servers/group.d.ts | 12 +- .../models/servers/group_membership.d.ts | 13 +- .../models/servers/groups_in_channel.d.ts | 9 +- .../models/servers/groups_in_team.d.ts | 9 +- types/database/models/servers/license.ts | 33 -- types/database/models/servers/my_channel.d.ts | 6 +- .../models/servers/my_channel_settings.d.ts | 8 +- types/database/models/servers/my_team.d.ts | 6 +- types/database/models/servers/post.d.ts | 24 +- .../models/servers/post_metadata.d.ts | 11 +- .../models/servers/posts_in_channel.d.ts | 6 +- .../models/servers/posts_in_thread.d.ts | 6 +- types/database/models/servers/preference.d.ts | 6 +- types/database/models/servers/reaction.d.ts | 9 +- types/database/models/servers/role.d.ts | 2 +- .../models/servers/slash_command.d.ts | 6 +- types/database/models/servers/system.d.ts | 2 +- types/database/models/servers/team.d.ts | 24 +- .../models/servers/team_channel_history.d.ts | 6 +- .../models/servers/team_membership.d.ts | 13 +- .../models/servers/team_search_history.d.ts | 6 +- .../models/servers/terms_of_service.d.ts | 2 +- types/database/models/servers/user.d.ts | 30 +- types/database/raw_values.d.ts | 108 ++++ types/global/preferences.d.ts | 2 +- 140 files changed, 1653 insertions(+), 2407 deletions(-) create mode 100644 app/actions/remote/preference.ts create mode 100644 app/actions/remote/team.ts create mode 100644 app/helpers/api/preference.ts create mode 100644 app/helpers/api/team.ts create mode 100644 app/queries/servers/preference.ts create mode 100644 app/queries/servers/team.ts create mode 100644 types/api/slash_command.d.ts delete mode 100644 types/database/index.d.ts delete mode 100644 types/database/models/servers/config.ts delete mode 100644 types/database/models/servers/license.ts create mode 100644 types/database/raw_values.d.ts diff --git a/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java b/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java index 3cf4c23afa..35574f109b 100644 --- a/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java +++ b/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java @@ -2,13 +2,11 @@ package com.mattermost.rnbeta; import com.mattermost.rnbeta.generated.BasePackageList; -import androidx.annotation.Nullable; import android.content.Context; import android.os.Bundle; import android.util.Log; -import java.lang.reflect.InvocationTargetException; import java.io.File; -import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -32,16 +30,10 @@ import com.facebook.react.ReactPackage; import com.facebook.react.ReactNativeHost; import com.facebook.react.TurboReactPackage; import com.facebook.react.bridge.NativeModule; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactMarker; -import com.facebook.react.bridge.ReactMarkerConstants; import com.facebook.react.bridge.JSIModulePackage; -import com.facebook.react.bridge.WritableMap; import com.facebook.react.module.model.ReactModuleInfo; import com.facebook.react.module.model.ReactModuleInfoProvider; -import com.facebook.react.modules.core.DeviceEventManagerModule; import com.facebook.react.modules.network.OkHttpClientProvider; import com.facebook.soloader.SoLoader; @@ -56,16 +48,6 @@ public class MainApplication extends NavigationApplication implements INotificat public Boolean sharedExtensionIsOpened = false; - public long APP_START_TIME; - - public long RELOAD; - public long CONTENT_APPEARED; - - public long PROCESS_PACKAGES_START; - public long PROCESS_PACKAGES_END; - - private Bundle mManagedConfig = null; - private final ReactModuleRegistryProvider mModuleRegistryProvider = new ReactModuleRegistryProvider(new BasePackageList().getPackageList(), null); private final ReactNativeHost mReactNativeHost = @@ -77,15 +59,14 @@ public class MainApplication extends NavigationApplication implements INotificat @Override protected List getPackages() { - @SuppressWarnings("UnnecessaryLocalVariable") List packages = new PackageList(this).getPackages(); // Packages that cannot be autolinked yet can be added manually here, for example: // packages.add(new MyReactNativePackage()); packages.add(new RNNotificationsPackage(MainApplication.this)); // Add unimodules - List unimodules = Arrays.asList( - new ModuleRegistryAdapter(mModuleRegistryProvider) + List unimodules = Collections.singletonList( + new ModuleRegistryAdapter(mModuleRegistryProvider) ); packages.addAll(unimodules); @@ -107,15 +88,12 @@ public class MainApplication extends NavigationApplication implements INotificat @Override public ReactModuleInfoProvider getReactModuleInfoProvider() { - return new ReactModuleInfoProvider() { - @Override - public Map getReactModuleInfos() { - Map map = new HashMap<>(); - map.put("MattermostShare", new ReactModuleInfo("MattermostShare", "com.mattermost.share.ShareModule", false, false, true, false, false)); - map.put("NotificationPreferences", new ReactModuleInfo("NotificationPreferences", "com.mattermost.rnbeta.NotificationPreferencesModule", false, false, false, false, false)); - map.put("RNTextInputReset", new ReactModuleInfo("RNTextInputReset", "com.mattermost.rnbeta.RNTextInputResetModule", false, false, false, false, false)); - return map; - } + return () -> { + Map map = new HashMap<>(); + map.put("MattermostShare", new ReactModuleInfo("MattermostShare", "com.mattermost.share.ShareModule", false, false, true, false, false)); + map.put("NotificationPreferences", new ReactModuleInfo("NotificationPreferences", "com.mattermost.rnbeta.NotificationPreferencesModule", false, false, false, false, false)); + map.put("RNTextInputReset", new ReactModuleInfo("RNTextInputReset", "com.mattermost.rnbeta.RNTextInputResetModule", false, false, false, false, false)); + return map; }; } } @@ -175,54 +153,9 @@ public class MainApplication extends NavigationApplication implements INotificat return new CustomPushNotificationDrawer(context, defaultAppLaunchHelper); } - public ReactContext getRunningReactContext() { - if (mReactNativeHost == null) { - return null; - } - - return mReactNativeHost - .getReactInstanceManager() - .getCurrentReactContext(); - } - - private void addReactMarkerListener() { - ReactMarker.addListener(new ReactMarker.MarkerListener() { - @Override - public void logMarker(ReactMarkerConstants name, @Nullable String tag, int instanceKey) { - if (name.toString() == ReactMarkerConstants.RELOAD.toString()) { - APP_START_TIME = System.currentTimeMillis(); - RELOAD = System.currentTimeMillis(); - } else if (name.toString() == ReactMarkerConstants.PROCESS_PACKAGES_START.toString()) { - PROCESS_PACKAGES_START = System.currentTimeMillis(); - } else if (name.toString() == ReactMarkerConstants.PROCESS_PACKAGES_END.toString()) { - PROCESS_PACKAGES_END = System.currentTimeMillis(); - } else if (name.toString() == ReactMarkerConstants.CONTENT_APPEARED.toString()) { - CONTENT_APPEARED = System.currentTimeMillis(); - ReactContext ctx = getRunningReactContext(); - - if (ctx != null) { - WritableMap map = Arguments.createMap(); - - map.putDouble("appReload", RELOAD); - map.putDouble("appContentAppeared", CONTENT_APPEARED); - - map.putDouble("processPackagesStart", PROCESS_PACKAGES_START); - map.putDouble("processPackagesEnd", PROCESS_PACKAGES_END); - - ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class). - emit("nativeMetrics", map); - } - } - } - }); - } - /** * Loads Flipper in React Native templates. Call this in the onCreate method with something like * initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); - * - * @param context - * @param reactInstanceManager */ private static void initializeFlipper( Context context, ReactInstanceManager reactInstanceManager) { @@ -236,13 +169,7 @@ public class MainApplication extends NavigationApplication implements INotificat aClass .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class) .invoke(null, context, reactInstanceManager); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { + } catch (Exception e) { e.printStackTrace(); } } diff --git a/app/actions/local/timezone.ts b/app/actions/local/timezone.ts index f62d00bc3f..f234d1dc1d 100644 --- a/app/actions/local/timezone.ts +++ b/app/actions/local/timezone.ts @@ -6,10 +6,9 @@ import {getTimeZone} from 'react-native-localize'; import DatabaseManager from '@database/manager'; import {queryUserById} from '@queries/servers/user'; import {updateMe} from '@actions/remote/user'; -import {Config} from '@typings/database/models/servers/config'; import User from '@typings/database/models/servers/user'; -export const isTimezoneEnabled = (config: Partial) => { +export const isTimezoneEnabled = (config: Partial) => { return config?.ExperimentalTimezone === 'true'; }; diff --git a/app/actions/remote/general.ts b/app/actions/remote/general.ts index 8c4061dd54..4d028d891d 100644 --- a/app/actions/remote/general.ts +++ b/app/actions/remote/general.ts @@ -1,14 +1,17 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {SYSTEM_IDENTIFIERS} from '@constants/database'; +import {DeviceEventEmitter} from 'react-native'; + +import {General} from '@constants'; import DatabaseManager from '@database/manager'; -import {getServerCredentials} from '@init/credentials'; import NetworkManager from '@init/network_manager'; +import {queryCurrentUserId} from '@queries/servers/system'; import type {ClientResponse} from '@mattermost/react-native-network-client'; +import type {Client4Error} from '@typings/api/client'; -import type {RawSystem} from '@typings/database/database'; +const HTTP_UNAUTHORIZED = 401; export const doPing = async (serverUrl: string) => { const client = await NetworkManager.createClient(serverUrl); @@ -46,41 +49,32 @@ export const doPing = async (serverUrl: string) => { return {error: undefined}; }; -export const fetchConfigAndLicense = async (serverUrl: string) => { - let client; - try { - client = NetworkManager.getClient(serverUrl); - } catch (error) { - return {error}; +export const forceLogoutIfNecessary = async (serverUrl: string, err: Client4Error) => { + const database = DatabaseManager.serverDatabases[serverUrl]?.database; + if (!database) { + return {error: `${serverUrl} database not found`}; } - try { - const [config, license] = await Promise.all([ - client.getClientConfigOld(), - client.getClientLicenseOld(), - ]); + const currentUserId = await queryCurrentUserId(database); - // If we have credentials for this server then update the values in the database - const credentials = await getServerCredentials(serverUrl); - const operator = DatabaseManager.serverDatabases[serverUrl]?.operator; - if (credentials && operator) { - const systems: RawSystem[] = [{ - id: SYSTEM_IDENTIFIERS.CONFIG, - value: JSON.stringify(config), - }, { - id: SYSTEM_IDENTIFIERS.LICENSE, - value: JSON.stringify(license), - }]; - - operator.handleSystem({systems, prepareRecordsOnly: false}). - catch((error) => { - // eslint-disable-next-line no-console - console.log('An error ocurred while saving config & license', error); - }); - } - - return {config, license}; - } catch (error) { - return {error}; + if ('status_code' in err && err.status_code === HTTP_UNAUTHORIZED && err?.url?.indexOf('/login') === -1 && currentUserId) { + await logout(serverUrl); } + + return {error: null}; +}; + +export const logout = async (serverUrl: string, skipServerLogout = false) => { + if (!skipServerLogout) { + try { + const client = NetworkManager.getClient(serverUrl); + await client.logout(); + } catch (error) { + // We want to log the user even if logging out from the server failed + // eslint-disable-next-line no-console + console.warn('An error ocurred loging out from the server', serverUrl, error); + } + } + + DeviceEventEmitter.emit(General.SERVER_LOGOUT, serverUrl); }; diff --git a/app/actions/remote/preference.ts b/app/actions/remote/preference.ts new file mode 100644 index 0000000000..2440431f95 --- /dev/null +++ b/app/actions/remote/preference.ts @@ -0,0 +1,40 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import DatabaseManager from '@database/manager'; +import NetworkManager from '@init/network_manager'; + +import {forceLogoutIfNecessary} from './general'; + +export type MyPreferencesRequest = { + preferences?: PreferenceType[]; + error?: never; +} + +export const fetchMyPreferences = async (serverUrl: string, fetchOnly = false): Promise => { + let client; + try { + client = NetworkManager.getClient(serverUrl); + } catch (error) { + return {error}; + } + + try { + const preferences = await client.getMyPreferences(); + + if (!fetchOnly) { + const operator = DatabaseManager.serverDatabases[serverUrl]?.operator; + if (operator) { + operator.handlePreferences({ + prepareRecordsOnly: false, + preferences, + }); + } + } + + return {preferences}; + } catch (error) { + forceLogoutIfNecessary(serverUrl, error); + return {error}; + } +}; diff --git a/app/actions/remote/push_notification.ts b/app/actions/remote/push_notification.ts index fc33844c29..dfe37e8047 100644 --- a/app/actions/remote/push_notification.ts +++ b/app/actions/remote/push_notification.ts @@ -8,7 +8,6 @@ import DatabaseManager from '@database/manager'; import PushNotifications from '@init/push_notifications'; import {queryCommonSystemValues} from '@app/queries/servers/system'; import {getSessions} from '@actions/remote/user'; -import {Config} from '@typings/database/models/servers/config'; const sortByNewest = (a: Session, b: Session) => { if (a.create_at > b.create_at) { @@ -20,7 +19,7 @@ const sortByNewest = (a: Session, b: Session) => { export const scheduleExpiredNotification = async (serverUrl: string, intl: IntlShape) => { const database = DatabaseManager.serverDatabases[serverUrl].database; - const {currentUserId, config}: {currentUserId: string; config: Partial} = await queryCommonSystemValues(database); + const {currentUserId, config}: {currentUserId: string; config: Partial} = await queryCommonSystemValues(database); if (config.ExtendSessionLengthWithActivity === 'true') { PushNotifications.cancelAllLocalNotifications(); diff --git a/app/actions/remote/systems.ts b/app/actions/remote/systems.ts index 1b321432b7..623b9c9461 100644 --- a/app/actions/remote/systems.ts +++ b/app/actions/remote/systems.ts @@ -2,14 +2,19 @@ // See LICENSE.txt for license information. import {logError} from '@actions/remote/error'; -import {forceLogoutIfNecessary} from '@actions/remote/user'; +import {forceLogoutIfNecessary} from '@actions/remote/general'; import {SYSTEM_IDENTIFIERS} from '@constants/database'; import DatabaseManager from '@database/manager'; +import {getServerCredentials} from '@init/credentials'; import NetworkManager from '@init/network_manager'; -import type {RawSystem} from '@typings/database/database'; +export type ConfigAndLicenseRequest = { + config?: ClientConfig; + license?: ClientLicense; + error?: never; +} -export const getDataRetentionPolicy = async (serverUrl: string) => { +export const fetchDataRetentionPolicy = async (serverUrl: string) => { let client; try { client = NetworkManager.getClient(serverUrl); @@ -29,7 +34,7 @@ export const getDataRetentionPolicy = async (serverUrl: string) => { const operator = DatabaseManager.serverDatabases[serverUrl]?.operator; if (operator) { - const systems: RawSystem[] = [{ + const systems: IdValue[] = [{ id: SYSTEM_IDENTIFIERS.DATA_RETENTION_POLICIES, value: JSON.stringify(data), }]; @@ -43,3 +48,45 @@ export const getDataRetentionPolicy = async (serverUrl: string) => { return data; }; + +export const fetchConfigAndLicense = async (serverUrl: string, fetchOnly = false): Promise => { + let client; + try { + client = NetworkManager.getClient(serverUrl); + } catch (error) { + return {error}; + } + + try { + const [config, license] = await Promise.all([ + client.getClientConfigOld(), + client.getClientLicenseOld(), + ]); + + // If we have credentials for this server then update the values in the database + if (!fetchOnly) { + const credentials = await getServerCredentials(serverUrl); + const operator = DatabaseManager.serverDatabases[serverUrl]?.operator; + if (credentials && operator) { + const systems: IdValue[] = [{ + id: SYSTEM_IDENTIFIERS.CONFIG, + value: JSON.stringify(config), + }, { + id: SYSTEM_IDENTIFIERS.LICENSE, + value: JSON.stringify(license), + }]; + + operator.handleSystem({systems, prepareRecordsOnly: false}). + catch((error) => { + // eslint-disable-next-line no-console + console.log('An error ocurred while saving config & license', error); + }); + } + } + + return {config, license}; + } catch (error) { + forceLogoutIfNecessary(serverUrl, error); + return {error}; + } +}; diff --git a/app/actions/remote/team.ts b/app/actions/remote/team.ts new file mode 100644 index 0000000000..3aefee2030 --- /dev/null +++ b/app/actions/remote/team.ts @@ -0,0 +1,57 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {Model} from '@nozbe/watermelondb'; + +import DatabaseManager from '@database/manager'; +import NetworkManager from '@init/network_manager'; +import {prepareMyTeams} from '@queries/servers/team'; + +import {forceLogoutIfNecessary} from './general'; + +export type MyTeamsRequest = { + teams?: Team[]; + memberships?: TeamMembership[]; + unreads?: TeamUnread[]; + error?: never; +} + +export const fetchMyTeams = async (serverUrl: string, fetchOnly = false): Promise => { + let client; + try { + client = NetworkManager.getClient(serverUrl); + } catch (error) { + return {error}; + } + + try { + const [teams, memberships, unreads] = await Promise.all([ + client.getMyTeams(), + client.getMyTeamMembers(), + client.getMyTeamUnreads(), + ]); + + if (!fetchOnly) { + const operator = DatabaseManager.serverDatabases[serverUrl]?.operator; + const modelPromises: Array> = []; + if (operator) { + const prepare = prepareMyTeams(operator, teams, memberships, unreads); + if (prepare) { + modelPromises.push(...prepare); + } + if (modelPromises.length) { + const models = await Promise.all(modelPromises); + const flattenedModels = models.flat() as Model[]; + if (flattenedModels?.length > 0) { + await operator.batchRecords(flattenedModels); + } + } + } + } + + return {teams, memberships, unreads}; + } catch (error) { + forceLogoutIfNecessary(serverUrl, error); + return {error}; + } +}; diff --git a/app/actions/remote/user.ts b/app/actions/remote/user.ts index 78cf1cdb27..3b7558b0ee 100644 --- a/app/actions/remote/user.ts +++ b/app/actions/remote/user.ts @@ -1,42 +1,39 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {DeviceEventEmitter} from 'react-native'; - import {autoUpdateTimezone, getDeviceTimezone, isTimezoneEnabled} from '@actions/local/timezone'; import {logError} from '@actions/remote/error'; import {loadRolesIfNeeded} from '@actions/remote/role'; -import {getDataRetentionPolicy} from '@actions/remote/systems'; -import {Database, General} from '@constants'; +import {fetchDataRetentionPolicy} from '@actions/remote/systems'; +import {Database} from '@constants'; import DatabaseManager from '@database/manager'; import analytics from '@init/analytics'; import NetworkManager from '@init/network_manager'; import {queryDeviceToken} from '@queries/app/global'; -import {queryCommonSystemValues, queryCurrentUserId} from '@queries/servers/system'; +import {queryCommonSystemValues} from '@queries/servers/system'; import {getCSRFFromCookie} from '@utils/security'; import type {Client4Error} from '@typings/api/client'; -import type {Config} from '@typings/database/models/servers/config'; -import type {LoadMeArgs, LoginArgs, RawMyTeam, RawPreference, - RawRole, RawTeam, RawTeamMembership, RawUser} from '@typings/database/database'; -import type {License} from '@typings/database/models/servers/license'; -import type Role from '@typings/database/models/servers/role'; -import type User from '@typings/database/models/servers/user'; +import type {LoadMeArgs, LoginArgs} from '@typings/database/database'; +import type RoleModel from '@typings/database/models/servers/role'; +import type UserModel from '@typings/database/models/servers/user'; + +import {forceLogoutIfNecessary} from './general'; + +// import {initAfterLogin} from './init'; type LoadedUser = { - currentUser?: RawUser; + currentUser?: UserProfile; error?: Client4Error; } -const HTTP_UNAUTHORIZED = 401; - -export const completeLogin = async (serverUrl: string, user: RawUser) => { +export const completeLogin = async (serverUrl: string, user: UserProfile) => { const database = DatabaseManager.serverDatabases[serverUrl]?.database; if (!database) { return {error: `${serverUrl} database not found`}; } - const {config, license}: { config: Partial; license: Partial } = await queryCommonSystemValues(database); + const {config, license}: { config: Partial; license: Partial } = await queryCommonSystemValues(database); if (!Object.keys(config)?.length || !Object.keys(license)?.length) { return null; @@ -50,27 +47,12 @@ export const completeLogin = async (serverUrl: string, user: RawUser) => { // Data retention if (config?.DataRetentionEnableMessageDeletion === 'true' && license?.IsLicensed === 'true' && license?.DataRetention === 'true') { - getDataRetentionPolicy(serverUrl); + fetchDataRetentionPolicy(serverUrl); } return null; }; -export const forceLogoutIfNecessary = async (serverUrl: string, err: Client4Error) => { - const database = DatabaseManager.serverDatabases[serverUrl]?.database; - if (!database) { - return {error: `${serverUrl} database not found`}; - } - - const currentUserId = await queryCurrentUserId(database); - - if ('status_code' in err && err.status_code === HTTP_UNAUTHORIZED && err?.url?.indexOf('/login') === -1 && currentUserId) { - await logout(serverUrl); - } - - return {error: null}; -}; - export const getSessions = async (serverUrl: string, currentUserId: string) => { let client; try { @@ -91,7 +73,7 @@ export const getSessions = async (serverUrl: string, currentUserId: string) => { export const login = async (serverUrl: string, {ldapOnly = false, loginId, mfaToken, password}: LoginArgs) => { let deviceToken; - let user: RawUser; + let user: UserProfile; const appDatabase = DatabaseManager.appDatabase?.database; if (!appDatabase) { @@ -107,13 +89,13 @@ export const login = async (serverUrl: string, {ldapOnly = false, loginId, mfaTo try { deviceToken = await queryDeviceToken(appDatabase); - user = (await client.login( + user = await client.login( loginId, password, mfaToken, deviceToken, ldapOnly, - ) as unknown) as RawUser; + ); await DatabaseManager.createServerDatabase({ config: { @@ -134,6 +116,8 @@ export const login = async (serverUrl: string, {ldapOnly = false, loginId, mfaTo await completeLogin(serverUrl, user); } + // initAfterLogin({serverUrl, user, deviceToken}); + return {error: undefined}; }; @@ -158,7 +142,7 @@ export const loadMe = async (serverUrl: string, {deviceToken, user}: LoadMeArgs) } if (!currentUser) { - currentUser = (await client.getMe() as unknown) as RawUser; + currentUser = await client.getMe(); } } catch (e) { await forceLogoutIfNecessary(serverUrl, e); @@ -186,7 +170,7 @@ export const loadMe = async (serverUrl: string, {deviceToken, user}: LoadMeArgs) const [ teams, - teamMembers, + teamMemberships, teamUnreads, preferences, config, @@ -201,17 +185,17 @@ export const loadMe = async (serverUrl: string, {deviceToken, user}: LoadMeArgs) ]); const operator = DatabaseManager.serverDatabases[serverUrl].operator; - const teamRecords = operator.handleTeam({prepareRecordsOnly: true, teams: teams as RawTeam[]}); - const teamMembershipRecords = operator.handleTeamMemberships({prepareRecordsOnly: true, teamMemberships: (teamMembers as unknown) as RawTeamMembership[]}); + const teamRecords = operator.handleTeam({prepareRecordsOnly: true, teams}); + const teamMembershipRecords = operator.handleTeamMemberships({prepareRecordsOnly: true, teamMemberships}); const myTeams = teamUnreads.map((unread) => { - const matchingTeam = teamMembers.find((team) => team.team_id === unread.team_id); + const matchingTeam = teamMemberships.find((team) => team.team_id === unread.team_id); return {team_id: unread.team_id, roles: matchingTeam?.roles ?? '', is_unread: unread.msg_count > 0, mentions_count: unread.mention_count}; }); const myTeamRecords = operator.handleMyTeam({ prepareRecordsOnly: true, - myTeams: (myTeams as unknown) as RawMyTeam[], + myTeams, }); const systemRecords = operator.handleSystem({ @@ -239,7 +223,7 @@ export const loadMe = async (serverUrl: string, {deviceToken, user}: LoadMeArgs) const preferenceRecords = operator.handlePreferences({ prepareRecordsOnly: true, - preferences: (preferences as unknown) as RawPreference[], + preferences, }); let roles: string[] = []; @@ -247,18 +231,18 @@ export const loadMe = async (serverUrl: string, {deviceToken, user}: LoadMeArgs) roles = roles.concat(role); } - for (const teamMember of teamMembers) { + for (const teamMember of teamMemberships) { roles = roles.concat(teamMember.roles.split(' ')); } const rolesToLoad = new Set(roles); - let rolesRecords: Role[] = []; + let rolesRecords: RoleModel[] = []; if (rolesToLoad.size > 0) { - const rolesByName = (await client.getRolesByNames(Array.from(rolesToLoad)) as unknown) as RawRole[]; + const rolesByName = await client.getRolesByNames(Array.from(rolesToLoad)); if (rolesByName?.length) { - rolesRecords = await operator.handleRole({prepareRecordsOnly: true, roles: rolesByName}) as Role[]; + rolesRecords = await operator.handleRole({prepareRecordsOnly: true, roles: rolesByName}); } } @@ -275,23 +259,6 @@ export const loadMe = async (serverUrl: string, {deviceToken, user}: LoadMeArgs) return {currentUser, error: undefined}; }; -export const logout = async (serverUrl: string, skipServerLogout = false) => { - if (!skipServerLogout) { - try { - const client = NetworkManager.getClient(serverUrl); - await client.logout(); - } catch (error) { - // We want to log the user even if logging out from the server failed - // eslint-disable-next-line no-console - console.warn('An error ocurred loging out from the server', serverUrl, error); - } - } - - DeviceEventEmitter.emit(General.SERVER_LOGOUT, serverUrl); - - return {data: true}; -}; - export const ssoLogin = async (serverUrl: string, bearerToken: string, csrfToken: string) => { let deviceToken; @@ -360,7 +327,7 @@ export const sendPasswordResetEmail = async (serverUrl: string, email: string) = }; }; -export const updateMe = async (serverUrl: string, user: User) => { +export const updateMe = async (serverUrl: string, user: UserModel) => { const database = DatabaseManager.serverDatabases[serverUrl]?.database; const operator = DatabaseManager.serverDatabases[serverUrl]?.operator; if (!database) { @@ -374,9 +341,9 @@ export const updateMe = async (serverUrl: string, user: User) => { return {error}; } - let data; + let data: UserProfile; try { - data = (await client.patchMe(user._raw) as unknown) as RawUser; + data = await client.patchMe(user._raw); } catch (e) { logError(e); return {error: e}; diff --git a/app/client/rest/preferences.ts b/app/client/rest/preferences.ts index 6c827393a7..aa5a0e21d9 100644 --- a/app/client/rest/preferences.ts +++ b/app/client/rest/preferences.ts @@ -4,7 +4,7 @@ export interface ClientPreferencesMix { savePreferences: (userId: string, preferences: PreferenceType[]) => Promise; deletePreferences: (userId: string, preferences: PreferenceType[]) => Promise; - getMyPreferences: () => Promise; + getMyPreferences: () => Promise; } const ClientPreferences = (superclass: any) => class extends superclass { diff --git a/app/constants/preferences.ts b/app/constants/preferences.ts index a8006af3cf..5d59c7f250 100644 --- a/app/constants/preferences.ts +++ b/app/constants/preferences.ts @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -const Preferences: Dictionary = { +const Preferences: Record = { CATEGORY_CHANNEL_OPEN_TIME: 'channel_open_time', CATEGORY_CHANNEL_APPROXIMATE_VIEW_TIME: 'channel_approximate_view_time', CATEGORY_DIRECT_CHANNEL_SHOW: 'direct_channel_show', @@ -39,6 +39,7 @@ const Preferences: Dictionary = { ADVANCED_CODE_BLOCK_ON_CTRL_ENTER: 'code_block_ctrl_enter', ADVANCED_SEND_ON_CTRL_ENTER: 'send_on_ctrl_enter', CATEGORY_THEME: 'theme', + TEAMS_ORDER: 'teams_order', THEMES: { default: { type: 'Mattermost', diff --git a/app/database/manager/__mocks__/index.ts b/app/database/manager/__mocks__/index.ts index d7d5036da1..d6acafd2b3 100644 --- a/app/database/manager/__mocks__/index.ts +++ b/app/database/manager/__mocks__/index.ts @@ -12,14 +12,14 @@ import urlParse from 'url-parse'; import {MIGRATION_EVENTS, MM_TABLES} from '@constants/database'; import AppDataOperator from '@database/operator/app_data_operator'; import AppDatabaseMigrations from '@app/database/migration/app'; -import {Info, Global, Servers} from '@app/database/models/app'; +import {InfoModel, GlobalModel, ServersModel} from '@database/models/app'; import {schema as appSchema} from '@app/database/schema/app'; import ServerDatabaseMigrations from '@database/migration/server'; -import {Channel, ChannelInfo, ChannelMembership, CustomEmoji, Draft, File, - Group, GroupMembership, GroupsInChannel, GroupsInTeam, MyChannel, MyChannelSettings, MyTeam, - Post, PostMetadata, PostsInChannel, PostsInThread, PreferenceModel, Reaction, Role, - SlashCommand, SystemModel, Team, TeamChannelHistory, TeamMembership, TeamSearchHistory, - TermsOfService, User, +import {ChannelModel, ChannelInfoModel, ChannelMembershipModel, CustomEmojiModel, DraftModel, FileModel, + GroupModel, GroupMembershipModel, GroupsInChannelModel, GroupsInTeamModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel, + PostModel, PostMetadataModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel, + SlashCommandModel, SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel, + TermsOfServiceModel, UserModel, } from '@database/models/server'; import {serverSchema} from '@database/schema/server'; import {queryActiveServer, queryServer} from '@queries/app/servers'; @@ -50,36 +50,13 @@ class DatabaseManager { private readonly serverModels: Models; constructor() { - this.appModels = [Info, Global, Servers]; + this.appModels = [InfoModel, GlobalModel, ServersModel]; this.serverModels = [ - Channel, - ChannelInfo, - ChannelMembership, - CustomEmoji, - Draft, - File, - Group, - GroupMembership, - GroupsInChannel, - GroupsInTeam, - MyChannel, - MyChannelSettings, - MyTeam, - Post, - PostMetadata, - PostsInChannel, - PostsInThread, - PreferenceModel, - Reaction, - Role, - SlashCommand, - SystemModel, - Team, - TeamChannelHistory, - TeamMembership, - TeamSearchHistory, - TermsOfService, - User, + ChannelModel, ChannelInfoModel, ChannelMembershipModel, CustomEmojiModel, DraftModel, FileModel, + GroupModel, GroupMembershipModel, GroupsInChannelModel, GroupsInTeamModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel, + PostModel, PostMetadataModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel, + SlashCommandModel, SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel, + TermsOfServiceModel, UserModel, ]; this.databaseDirectory = ''; } @@ -89,6 +66,14 @@ class DatabaseManager { for await (const serverUrl of serverUrls) { await this.initServerDatabase(serverUrl); } + this.appDatabase?.operator.handleInfo({ + info: [{ + build_number: '123', + created_at: Date.now(), + version_number: '2.0.0', + }], + prepareRecordsOnly: false, + }); }; private createAppDatabase = async (): Promise => { @@ -108,7 +93,7 @@ class DatabaseManager { return this.appDatabase; } catch (e) { - // TODO : report to sentry? Show something on the UI ? + // do nothing } return undefined; @@ -141,7 +126,7 @@ class DatabaseManager { return serverDatabase; } catch (e) { - // TODO : report to sentry? Show something on the UI ? + // do nothing } } @@ -160,7 +145,7 @@ class DatabaseManager { private addServerToAppDatabase = async ({databaseFilePath, displayName, serverUrl}: RegisterServerDatabaseArgs): Promise => { try { - const isServerPresent = await this.isServerPresent(serverUrl); // TODO: Use normalized serverUrl + const isServerPresent = await this.isServerPresent(serverUrl); if (this.appDatabase?.database && !isServerPresent) { const appDatabase = this.appDatabase.database; @@ -171,14 +156,14 @@ class DatabaseManager { server.displayName = displayName; server.mentionCount = 0; server.unreadCount = 0; - server.url = serverUrl; // TODO: Use normalized serverUrl + server.url = serverUrl; server.isSecured = urlParse(serverUrl).protocol === 'https'; server.lastActiveAt = 0; }); }); } } catch (e) { - // TODO : report to sentry? Show something on the UI ? + // do nothing } }; @@ -219,7 +204,7 @@ class DatabaseManager { await database.action(async () => { const servers = await database.collections.get(SERVERS).query(Q.where('url', serverUrl)).fetch(); if (servers.length) { - servers[0].update((server: Servers) => { + servers[0].update((server: ServersModel) => { server.lastActiveAt = Date.now(); }); } diff --git a/app/database/manager/index.ts b/app/database/manager/index.ts index 59304f493a..b1a35e5d7d 100644 --- a/app/database/manager/index.ts +++ b/app/database/manager/index.ts @@ -11,15 +11,15 @@ import urlParse from 'url-parse'; import {MIGRATION_EVENTS, MM_TABLES} from '@constants/database'; import AppDataOperator from '@database/operator/app_data_operator'; -import AppDatabaseMigrations from '@app/database/migration/app'; -import {Info, Global, Servers} from '@app/database/models/app'; -import {schema as appSchema} from '@app/database/schema/app'; +import AppDatabaseMigrations from '@database/migration/app'; +import {InfoModel, GlobalModel, ServersModel} from '@database/models/app'; +import {schema as appSchema} from '@database/schema/app'; import ServerDatabaseMigrations from '@database/migration/server'; -import {Channel, ChannelInfo, ChannelMembership, CustomEmoji, Draft, File, - Group, GroupMembership, GroupsInChannel, GroupsInTeam, MyChannel, MyChannelSettings, MyTeam, - Post, PostMetadata, PostsInChannel, PostsInThread, PreferenceModel, Reaction, Role, - SlashCommand, SystemModel, Team, TeamChannelHistory, TeamMembership, TeamSearchHistory, - TermsOfService, User, +import {ChannelModel, ChannelInfoModel, ChannelMembershipModel, CustomEmojiModel, DraftModel, FileModel, + GroupModel, GroupMembershipModel, GroupsInChannelModel, GroupsInTeamModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel, + PostModel, PostMetadataModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel, + SlashCommandModel, SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel, + TermsOfServiceModel, UserModel, } from '@database/models/server'; import {serverSchema} from '@database/schema/server'; import {queryActiveServer, queryServer} from '@queries/app/servers'; @@ -43,13 +43,13 @@ class DatabaseManager { private readonly serverModels: Models; constructor() { - this.appModels = [Info, Global, Servers]; + this.appModels = [InfoModel, GlobalModel, ServersModel]; this.serverModels = [ - Channel, ChannelInfo, ChannelMembership, CustomEmoji, Draft, File, - Group, GroupMembership, GroupsInChannel, GroupsInTeam, MyChannel, MyChannelSettings, MyTeam, - Post, PostMetadata, PostsInChannel, PostsInThread, PreferenceModel, Reaction, Role, - SlashCommand, SystemModel, Team, TeamChannelHistory, TeamMembership, TeamSearchHistory, - TermsOfService, User, + ChannelModel, ChannelInfoModel, ChannelMembershipModel, CustomEmojiModel, DraftModel, FileModel, + GroupModel, GroupMembershipModel, GroupsInChannelModel, GroupsInTeamModel, MyChannelModel, MyChannelSettingsModel, MyTeamModel, + PostModel, PostMetadataModel, PostsInChannelModel, PostsInThreadModel, PreferenceModel, ReactionModel, RoleModel, + SlashCommandModel, SystemModel, TeamModel, TeamChannelHistoryModel, TeamMembershipModel, TeamSearchHistoryModel, + TermsOfServiceModel, UserModel, ]; this.databaseDirectory = Platform.OS === 'ios' ? getIOSAppGroupDetails().appGroupDatabase : FileSystem.documentDirectory; @@ -182,7 +182,7 @@ class DatabaseManager { */ private addServerToAppDatabase = async ({databaseFilePath, displayName, serverUrl}: RegisterServerDatabaseArgs): Promise => { try { - const isServerPresent = await this.isServerPresent(serverUrl); // TODO: Use normalized serverUrl + const isServerPresent = await this.isServerPresent(serverUrl); if (this.appDatabase?.database && !isServerPresent) { const appDatabase = this.appDatabase.database; @@ -193,7 +193,7 @@ class DatabaseManager { server.displayName = displayName; server.mentionCount = 0; server.unreadCount = 0; - server.url = serverUrl; // TODO: Use normalized serverUrl + server.url = serverUrl; server.isSecured = urlParse(serverUrl).protocol === 'https'; server.lastActiveAt = 0; }); @@ -260,7 +260,7 @@ class DatabaseManager { await database.action(async () => { const servers = await database.collections.get(SERVERS).query(Q.where('url', serverUrl)).fetch(); if (servers.length) { - servers[0].update((server: Servers) => { + servers[0].update((server: ServersModel) => { server.lastActiveAt = Date.now(); }); } diff --git a/app/database/models/app/global.ts b/app/database/models/app/global.ts index 35ad965dae..18decdee41 100644 --- a/app/database/models/app/global.ts +++ b/app/database/models/app/global.ts @@ -15,7 +15,7 @@ const {GLOBAL} = MM_TABLES.APP; * The Global model will act as a dictionary of name-value pairs. The value field can be a JSON object or any other * data type. It will hold information that applies to the whole app ( e.g. sidebar settings for tablets) */ -export default class Global extends Model { +export default class GlobalModel extends Model { /** table (name) : global */ static table = GLOBAL; diff --git a/app/database/models/app/index.ts b/app/database/models/app/index.ts index 7f0c8c0fa4..fb380f6019 100644 --- a/app/database/models/app/index.ts +++ b/app/database/models/app/index.ts @@ -1,6 +1,6 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -export {default as Info} from './info'; -export {default as Global} from './global'; -export {default as Servers} from './servers'; +export {default as InfoModel} from './info'; +export {default as GlobalModel} from './global'; +export {default as ServersModel} from './servers'; diff --git a/app/database/models/app/info.ts b/app/database/models/app/info.ts index 1c331325bf..ef2bd7871c 100644 --- a/app/database/models/app/info.ts +++ b/app/database/models/app/info.ts @@ -12,7 +12,7 @@ const {INFO} = MM_TABLES.APP; * The App model will hold information - such as the version number, build number and creation date - * for the Mattermost mobile app. */ -export default class Info extends Model { +export default class InfoModel extends Model { /** table (name) : info */ static table = INFO; diff --git a/app/database/models/app/servers.ts b/app/database/models/app/servers.ts index a646618140..b2014fc943 100644 --- a/app/database/models/app/servers.ts +++ b/app/database/models/app/servers.ts @@ -12,7 +12,7 @@ const {SERVERS} = MM_TABLES.APP; * The Server model will help us to identify the various servers a user will log in; in the context of * multi-server support system. The db_path field will hold the App-Groups file-path */ -export default class Servers extends Model { +export default class ServersModel extends Model { /** table (name) : servers */ static table = SERVERS; diff --git a/app/database/models/server/channel.ts b/app/database/models/server/channel.ts index 4755dc933e..42a7fd0058 100644 --- a/app/database/models/server/channel.ts +++ b/app/database/models/server/channel.ts @@ -6,16 +6,17 @@ import {children, field, immutableRelation, lazy} from '@nozbe/watermelondb/deco import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; -import ChannelInfo from '@typings/database/models/servers/channel_info'; -import ChannelMembership from '@typings/database/models/servers/channel_membership'; -import Draft from '@typings/database/models/servers/draft'; -import GroupsInChannel from '@typings/database/models/servers/groups_in_channel'; -import MyChannel from '@typings/database/models/servers/my_channel'; -import MyChannelSettings from '@typings/database/models/servers/my_channel_settings'; -import Post from '@typings/database/models/servers/post'; -import PostsInChannel from '@typings/database/models/servers/posts_in_channel'; -import Team from '@typings/database/models/servers/team'; -import User from '@typings/database/models/servers/user'; + +import type ChannelInfoModel from '@typings/database/models/servers/channel_info'; +import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership'; +import type DraftModel from '@typings/database/models/servers/draft'; +import type GroupsInChannelModel from '@typings/database/models/servers/groups_in_channel'; +import type MyChannelModel from '@typings/database/models/servers/my_channel'; +import type MyChannelSettingsModel from '@typings/database/models/servers/my_channel_settings'; +import type PostModel from '@typings/database/models/servers/post'; +import type PostsInChannelModel from '@typings/database/models/servers/posts_in_channel'; +import type TeamModel from '@typings/database/models/servers/team'; +import type UserModel from '@typings/database/models/servers/user'; const { CHANNEL, @@ -34,7 +35,7 @@ const { /** * The Channel model represents a channel in the Mattermost app. */ -export default class Channel extends Model { +export default class ChannelModel extends Model { /** table (name) : Channel */ static table = CHANNEL; @@ -103,32 +104,32 @@ export default class Channel extends Model { @field('type') type!: string; /** members : Users belonging to this channel */ - @children(CHANNEL_MEMBERSHIP) members!: ChannelMembership[]; + @children(CHANNEL_MEMBERSHIP) members!: ChannelMembershipModel[]; /** drafts : All drafts for this channel */ - @children(DRAFT) drafts!: Draft[]; + @children(DRAFT) drafts!: DraftModel[]; /** groupsInChannel : Every group contained in this channel */ - @children(GROUPS_IN_CHANNEL) groupsInChannel!: GroupsInChannel[]; + @children(GROUPS_IN_CHANNEL) groupsInChannel!: GroupsInChannelModel[]; /** posts : All posts made in that channel */ - @children(POST) posts!: Post[]; + @children(POST) posts!: PostModel[]; /** postsInChannel : a section of the posts for that channel bounded by a range */ - @children(POSTS_IN_CHANNEL) postsInChannel!: PostsInChannel[]; + @children(POSTS_IN_CHANNEL) postsInChannel!: PostsInChannelModel[]; /** team : The TEAM to which this CHANNEL belongs */ - @immutableRelation(TEAM, 'team_id') team!: Relation; + @immutableRelation(TEAM, 'team_id') team!: Relation; /** creator : The USER who created this CHANNEL*/ - @immutableRelation(USER, 'creator_id') creator!: Relation; + @immutableRelation(USER, 'creator_id') creator!: Relation; /** info : Query returning extra information about this channel from CHANNEL_INFO table */ - @lazy info = this.collections.get(CHANNEL_INFO).query(Q.on(CHANNEL, 'id', this.id)) as Query; + @lazy info = this.collections.get(CHANNEL_INFO).query(Q.on(CHANNEL, 'id', this.id)) as Query; /** membership : Query returning the membership data for the current user if it belongs to this channel */ - @lazy membership = this.collections.get(MY_CHANNEL).query(Q.on(CHANNEL, 'id', this.id)) as Query; + @lazy membership = this.collections.get(MY_CHANNEL).query(Q.on(CHANNEL, 'id', this.id)) as Query; /** settings: User specific settings/preferences for this channel */ - @lazy settings = this.collections.get(MY_CHANNEL_SETTINGS).query(Q.on(CHANNEL, 'id', this.id)) as Query; + @lazy settings = this.collections.get(MY_CHANNEL_SETTINGS).query(Q.on(CHANNEL, 'id', this.id)) as Query; } diff --git a/app/database/models/server/channel_info.ts b/app/database/models/server/channel_info.ts index 4e7cd720e0..a0ed799425 100644 --- a/app/database/models/server/channel_info.ts +++ b/app/database/models/server/channel_info.ts @@ -6,7 +6,8 @@ import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; -import Channel from '@typings/database/models/servers/channel'; + +import type ChannelModel from '@typings/database/models/servers/channel'; const {CHANNEL, CHANNEL_INFO} = MM_TABLES.SERVER; @@ -15,7 +16,7 @@ const {CHANNEL, CHANNEL_INFO} = MM_TABLES.SERVER; * In a Separation of Concerns approach, ChannelInfo will provide additional information about a channel but on a more * specific level. */ -export default class ChannelInfo extends Model { +export default class ChannelInfoModel extends Model { /** table (name) : ChannelInfo */ static table = CHANNEL_INFO; @@ -45,5 +46,5 @@ export default class ChannelInfo extends Model { @field('purpose') purpose!: string; /** channel : The lazy query property to the record from CHANNEL table */ - @immutableRelation(CHANNEL, 'channel_id') channel!: Relation; + @immutableRelation(CHANNEL, 'channel_id') channel!: Relation; } diff --git a/app/database/models/server/channel_membership.ts b/app/database/models/server/channel_membership.ts index c645088796..b2422a411a 100644 --- a/app/database/models/server/channel_membership.ts +++ b/app/database/models/server/channel_membership.ts @@ -5,9 +5,10 @@ import {Q, Query, Relation} from '@nozbe/watermelondb'; import {field, immutableRelation, lazy} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Channel from '@typings/database/models/servers/channel'; import {MM_TABLES} from '@constants/database'; -import User from '@typings/database/models/servers/user'; + +import type ChannelModel from '@typings/database/models/servers/channel'; +import type UserModel from '@typings/database/models/servers/user'; const {CHANNEL, CHANNEL_MEMBERSHIP, USER} = MM_TABLES.SERVER; @@ -15,7 +16,7 @@ const {CHANNEL, CHANNEL_MEMBERSHIP, USER} = MM_TABLES.SERVER; * The ChannelMembership model represents the 'association table' where many channels have users and many users are on * channels ( N:N relationship between model Users and model Channel) */ -export default class ChannelMembership extends Model { +export default class ChannelMembershipModel extends Model { /** table (name) : ChannelMembership */ static table = CHANNEL_MEMBERSHIP; @@ -36,18 +37,18 @@ export default class ChannelMembership extends Model { @field('user_id') userId!: string; /** memberChannel : The related channel this member belongs to */ - @immutableRelation(CHANNEL, 'channel_id') memberChannel!: Relation; + @immutableRelation(CHANNEL, 'channel_id') memberChannel!: Relation; /** memberUser : The related member belonging to the channel */ - @immutableRelation(USER, 'user_id') memberUser!: Relation; + @immutableRelation(USER, 'user_id') memberUser!: Relation; /** * getAllChannelsForUser - Retrieves all the channels that the user is part of */ - @lazy getAllChannelsForUser = this.collections.get(CHANNEL).query(Q.on(USER, 'id', this.userId)) as Query; + @lazy getAllChannelsForUser = this.collections.get(CHANNEL).query(Q.on(USER, 'id', this.userId)) as Query; /** * getAllUsersInChannel - Retrieves all the users who are part of this channel */ - @lazy getAllUsersInChannel = this.collections.get(USER).query(Q.on(CHANNEL, 'id', this.channelId)) as Query; + @lazy getAllUsersInChannel = this.collections.get(USER).query(Q.on(CHANNEL, 'id', this.channelId)) as Query; } diff --git a/app/database/models/server/custom_emoji.ts b/app/database/models/server/custom_emoji.ts index a28d32495b..b20bf616f6 100644 --- a/app/database/models/server/custom_emoji.ts +++ b/app/database/models/server/custom_emoji.ts @@ -9,7 +9,7 @@ import {MM_TABLES} from '@constants/database'; const {CUSTOM_EMOJI} = MM_TABLES.SERVER; /** The CustomEmoji model describes all the custom emojis used in the Mattermost app */ -export default class CustomEmoji extends Model { +export default class CustomEmojiModel extends Model { /** table (name) : CustomEmoji */ static table = CUSTOM_EMOJI; diff --git a/app/database/models/server/draft.ts b/app/database/models/server/draft.ts index a7258e22cc..8a9e1fa5e7 100644 --- a/app/database/models/server/draft.ts +++ b/app/database/models/server/draft.ts @@ -12,7 +12,7 @@ const {CHANNEL, DRAFT, POST} = MM_TABLES.SERVER; /** * The Draft model represents the draft state of messages in Direct/Group messages and in channels */ -export default class Draft extends Model { +export default class DraftModel extends Model { /** table (name) : Draft */ static table = DRAFT; diff --git a/app/database/models/server/file.ts b/app/database/models/server/file.ts index f2154b3e0b..0120754a20 100644 --- a/app/database/models/server/file.ts +++ b/app/database/models/server/file.ts @@ -6,14 +6,15 @@ import Model, {Associations} from '@nozbe/watermelondb/Model'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import {MM_TABLES} from '@constants/database'; -import Post from '@typings/database/models/servers/post'; + +import type PostModel from '@typings/database/models/servers/post'; const {FILE, POST} = MM_TABLES.SERVER; /** * The File model works in pair with the Post model. It hosts information about the files shared in a Post */ -export default class File extends Model { +export default class FileModel extends Model { /** table (name) : File */ static table = FILE; @@ -52,5 +53,5 @@ export default class File extends Model { @field('width') width!: number; /** post : The related Post record for this file */ - @immutableRelation(POST, 'post_id') post!: Relation; + @immutableRelation(POST, 'post_id') post!: Relation; } diff --git a/app/database/models/server/group.ts b/app/database/models/server/group.ts index e496d9a1b4..7cbbcd6dee 100644 --- a/app/database/models/server/group.ts +++ b/app/database/models/server/group.ts @@ -5,9 +5,10 @@ import Model, {Associations} from '@nozbe/watermelondb/Model'; import {children, field} from '@nozbe/watermelondb/decorators'; import {MM_TABLES} from '@constants/database'; -import GroupMembership from '@typings/database/models/servers/group_membership'; -import GroupsInChannel from '@typings/database/models/servers/groups_in_channel'; -import GroupsInTeam from '@typings/database/models/servers/groups_in_team'; + +import type GroupMembershipModel from '@typings/database/models/servers/group_membership'; +import type GroupsInChannelModel from '@typings/database/models/servers/groups_in_channel'; +import type GroupsInTeamModel from '@typings/database/models/servers/groups_in_team'; const {GROUP, GROUPS_IN_CHANNEL, GROUPS_IN_TEAM, GROUP_MEMBERSHIP} = MM_TABLES.SERVER; @@ -16,7 +17,7 @@ const {GROUP, GROUPS_IN_CHANNEL, GROUPS_IN_TEAM, GROUP_MEMBERSHIP} = MM_TABLES.S * all users who are in the mobile team. If one needs to send that group a message, then s/he can mention the group's * name in the message. (e.g @mobile_team) */ -export default class Group extends Model { +export default class GroupModel extends Model { /** table (name) : Group */ static table = GROUP; @@ -40,11 +41,11 @@ export default class Group extends Model { @field('name') name!: string; /** groupsInChannel : All the related children records from GroupsInChannel */ - @children(GROUPS_IN_CHANNEL) groupsInChannel!: GroupsInChannel[]; + @children(GROUPS_IN_CHANNEL) groupsInChannel!: GroupsInChannelModel[]; /** groupsInTeam : All the related children records from GroupsInTeam */ - @children(GROUPS_IN_TEAM) groupsInTeam!: GroupsInTeam[]; + @children(GROUPS_IN_TEAM) groupsInTeam!: GroupsInTeamModel[]; /** groupMemberships : All the related children records from GroupMembership */ - @children(GROUP_MEMBERSHIP) groupMemberships!: GroupMembership[]; + @children(GROUP_MEMBERSHIP) groupMemberships!: GroupMembershipModel[]; } diff --git a/app/database/models/server/group_membership.ts b/app/database/models/server/group_membership.ts index b5a2aa72da..c8729ea36c 100644 --- a/app/database/models/server/group_membership.ts +++ b/app/database/models/server/group_membership.ts @@ -6,8 +6,9 @@ import {field, immutableRelation, lazy} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; -import Group from '@typings/database/models/servers/group'; -import User from '@typings/database/models/servers/user'; + +import type GroupModel from '@typings/database/models/servers/group'; +import type UserModel from '@typings/database/models/servers/user'; const {GROUP, GROUP_MEMBERSHIP, USER} = MM_TABLES.SERVER; @@ -15,7 +16,7 @@ const {GROUP, GROUP_MEMBERSHIP, USER} = MM_TABLES.SERVER; * The GroupMembership model represents the 'association table' where many groups have users and many users are in * groups (relationship type N:N) */ -export default class GroupMembership extends Model { +export default class GroupMembershipModel extends Model { /** table (name) : GroupMembership */ static table = GROUP_MEMBERSHIP; @@ -36,18 +37,18 @@ export default class GroupMembership extends Model { @field('user_id') userId!: string; /** memberGroup : The related group this user belongs to */ - @immutableRelation(GROUP, 'group_id') memberGroup!: Relation; + @immutableRelation(GROUP, 'group_id') memberGroup!: Relation; /** memberUser : The related user in the group */ - @immutableRelation(USER, 'user_id') memberUser!: Relation; + @immutableRelation(USER, 'user_id') memberUser!: Relation; /** * getAllGroupsForUser : Retrieves all the groups that the user is part of */ - @lazy getAllGroupsForUser = this.collections.get(GROUP).query(Q.on(USER, 'id', this.userId)) as Query; + @lazy getAllGroupsForUser = this.collections.get(GROUP).query(Q.on(USER, 'id', this.userId)) as Query; /** * getAllUsersInGroup : Retrieves all the users who are part of this group */ - @lazy getAllUsersInGroup = this.collections.get(USER).query(Q.on(GROUP, 'id', this.groupId)) as Query; + @lazy getAllUsersInGroup = this.collections.get(USER).query(Q.on(GROUP, 'id', this.groupId)) as Query; } diff --git a/app/database/models/server/groups_in_channel.ts b/app/database/models/server/groups_in_channel.ts index 1053211cf6..0b09489d04 100644 --- a/app/database/models/server/groups_in_channel.ts +++ b/app/database/models/server/groups_in_channel.ts @@ -6,15 +6,16 @@ import Model, {Associations} from '@nozbe/watermelondb/Model'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import {MM_TABLES} from '@constants/database'; -import Channel from '@typings/database/models/servers/channel'; -import Group from '@typings/database/models/servers/group'; + +import type ChannelModel from '@typings/database/models/servers/channel'; +import type GroupModel from '@typings/database/models/servers/group'; const {GROUP, GROUPS_IN_CHANNEL, CHANNEL} = MM_TABLES.SERVER; /** * The GroupsInChannel links the Channel model with the Group model */ -export default class GroupsInChannel extends Model { +export default class GroupsInChannelModel extends Model { /** table (name) : GroupsInChannel */ static table = GROUPS_IN_CHANNEL; @@ -41,8 +42,8 @@ export default class GroupsInChannel extends Model { @field('timezone_count') timezoneCount!: number; /** channel : The related record to the parent Channel model */ - @immutableRelation(CHANNEL, 'channel_id') channel!: Relation; + @immutableRelation(CHANNEL, 'channel_id') channel!: Relation; /** group : The related record to the parent Group model */ - @immutableRelation(GROUP, 'group_id') group!: Relation; + @immutableRelation(GROUP, 'group_id') group!: Relation; } diff --git a/app/database/models/server/groups_in_team.ts b/app/database/models/server/groups_in_team.ts index c67640f025..b15825dee8 100644 --- a/app/database/models/server/groups_in_team.ts +++ b/app/database/models/server/groups_in_team.ts @@ -5,16 +5,17 @@ import {Relation} from '@nozbe/watermelondb'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Group from '@typings/database/models/servers/group'; import {MM_TABLES} from '@constants/database'; -import Team from '@typings/database/models/servers/team'; + +import type GroupModel from '@typings/database/models/servers/group'; +import type TeamModel from '@typings/database/models/servers/team'; const {GROUP, GROUPS_IN_TEAM, TEAM} = MM_TABLES.SERVER; /** * The GroupsInTeam links the Team model with the Group model */ -export default class GroupsInTeam extends Model { +export default class GroupsInTeamModel extends Model { /** table (name) : GroupsInTeam */ static table = GROUPS_IN_TEAM; @@ -35,8 +36,8 @@ export default class GroupsInTeam extends Model { @field('team_id') teamId!: string; /** team : The related record to the parent Team model */ - @immutableRelation(TEAM, 'team_id') team!: Relation; + @immutableRelation(TEAM, 'team_id') team!: Relation; /** group : The related record to the parent Team model */ - @immutableRelation(GROUP, 'group_id') group!: Relation; + @immutableRelation(GROUP, 'group_id') group!: Relation; } diff --git a/app/database/models/server/index.ts b/app/database/models/server/index.ts index e3e6c0b686..36cdf8357d 100644 --- a/app/database/models/server/index.ts +++ b/app/database/models/server/index.ts @@ -1,31 +1,31 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -export {default as ChannelInfo} from './channel_info'; -export {default as ChannelMembership} from './channel_membership'; -export {default as Channel} from './channel'; -export {default as CustomEmoji} from './custom_emoji'; -export {default as Draft} from './draft'; -export {default as File} from './file'; -export {default as GroupMembership} from './group_membership'; -export {default as GroupsInChannel} from './groups_in_channel'; -export {default as GroupsInTeam} from './groups_in_team'; -export {default as Group} from './group'; -export {default as MyChannelSettings} from './my_channel_settings'; -export {default as MyChannel} from './my_channel'; -export {default as MyTeam} from './my_team'; -export {default as PostMetadata} from './post_metadata'; -export {default as PostsInChannel} from './posts_in_channel'; -export {default as PostsInThread} from './posts_in_thread'; -export {default as Post} from './post'; +export {default as ChannelInfoModel} from './channel_info'; +export {default as ChannelMembershipModel} from './channel_membership'; +export {default as ChannelModel} from './channel'; +export {default as CustomEmojiModel} from './custom_emoji'; +export {default as DraftModel} from './draft'; +export {default as FileModel} from './file'; +export {default as GroupMembershipModel} from './group_membership'; +export {default as GroupsInChannelModel} from './groups_in_channel'; +export {default as GroupsInTeamModel} from './groups_in_team'; +export {default as GroupModel} from './group'; +export {default as MyChannelSettingsModel} from './my_channel_settings'; +export {default as MyChannelModel} from './my_channel'; +export {default as MyTeamModel} from './my_team'; +export {default as PostMetadataModel} from './post_metadata'; +export {default as PostsInChannelModel} from './posts_in_channel'; +export {default as PostsInThreadModel} from './posts_in_thread'; +export {default as PostModel} from './post'; export {default as PreferenceModel} from './preference'; -export {default as Reaction} from './reaction'; -export {default as Role} from './role'; -export {default as SlashCommand} from './slash_command'; +export {default as ReactionModel} from './reaction'; +export {default as RoleModel} from './role'; +export {default as SlashCommandModel} from './slash_command'; export {default as SystemModel} from './system'; -export {default as TeamChannelHistory} from './team_channel_history'; -export {default as TeamMembership} from './team_membership'; -export {default as TeamSearchHistory} from './team_search_history'; -export {default as Team} from './team'; -export {default as TermsOfService} from './terms_of_service'; -export {default as User} from './user'; +export {default as TeamChannelHistoryModel} from './team_channel_history'; +export {default as TeamMembershipModel} from './team_membership'; +export {default as TeamSearchHistoryModel} from './team_search_history'; +export {default as TeamModel} from './team'; +export {default as TermsOfServiceModel} from './terms_of_service'; +export {default as UserModel} from './user'; diff --git a/app/database/models/server/my_channel.ts b/app/database/models/server/my_channel.ts index abe8c61d70..5384f6f297 100644 --- a/app/database/models/server/my_channel.ts +++ b/app/database/models/server/my_channel.ts @@ -5,15 +5,16 @@ import {Relation} from '@nozbe/watermelondb'; import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Channel from '@typings/database/models/servers/channel'; import {MM_TABLES} from '@constants/database'; +import type ChannelModel from '@typings/database/models/servers/channel'; + const {CHANNEL, MY_CHANNEL} = MM_TABLES.SERVER; /** * MyChannel is an extension of the Channel model but it lists only the Channels the app's user belongs to */ -export default class MyChannel extends Model { +export default class MyChannelModel extends Model { /** table (name) : MyChannel */ static table = MY_CHANNEL; @@ -43,5 +44,5 @@ export default class MyChannel extends Model { @field('roles') roles!: string; /** channel : The relation pointing to the CHANNEL table */ - @immutableRelation(CHANNEL, 'channel_id') channel!: Relation; + @immutableRelation(CHANNEL, 'channel_id') channel!: Relation; } diff --git a/app/database/models/server/my_channel_settings.ts b/app/database/models/server/my_channel_settings.ts index 3c65d46a9a..df92a95656 100644 --- a/app/database/models/server/my_channel_settings.ts +++ b/app/database/models/server/my_channel_settings.ts @@ -8,7 +8,7 @@ import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; import {safeParseJSON} from '@utils/helpers'; -import type Channel from '@typings/database/models/servers/channel'; +import type ChannelModel from '@typings/database/models/servers/channel'; const {CHANNEL, MY_CHANNEL_SETTINGS} = MM_TABLES.SERVER; @@ -16,7 +16,7 @@ const {CHANNEL, MY_CHANNEL_SETTINGS} = MM_TABLES.SERVER; * The MyChannelSettings model represents the specific user's configuration to * the channel this user belongs to. */ -export default class MyChannelSettings extends Model { +export default class MyChannelSettingsModel extends Model { /** table (name) : MyChannelSettings */ static table = MY_CHANNEL_SETTINGS; @@ -31,8 +31,8 @@ export default class MyChannelSettings extends Model { @field('channel_id') channelId!: string; /** notify_props : Configurations with regards to this channel */ - @json('notify_props', safeParseJSON) notifyProps!: NotifyProps; + @json('notify_props', safeParseJSON) notifyProps!: ChannelNotifyProps; /** channel : The relation pointing to the CHANNEL table */ - @immutableRelation(CHANNEL, 'channel_id') channel!: Relation; + @immutableRelation(CHANNEL, 'channel_id') channel!: Relation; } diff --git a/app/database/models/server/my_team.ts b/app/database/models/server/my_team.ts index 801578e054..2073303e8e 100644 --- a/app/database/models/server/my_team.ts +++ b/app/database/models/server/my_team.ts @@ -6,14 +6,15 @@ import {field, relation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; -import Team from '@typings/database/models/servers/team'; + +import type TeamModel from '@typings/database/models/servers/team'; const {TEAM, MY_TEAM} = MM_TABLES.SERVER; /** * MyTeam represents only the teams that the current user belongs to */ -export default class MyTeam extends Model { +export default class MyTeamModel extends Model { /** table (name) : MyTeam */ static table = MY_TEAM; @@ -37,5 +38,5 @@ export default class MyTeam extends Model { @field('team_id') teamId!: string; /** team : The relation to the TEAM, that this user belongs to */ - @relation(MY_TEAM, 'team_id') team!: Relation; + @relation(MY_TEAM, 'team_id') team!: Relation; } diff --git a/app/database/models/server/post.ts b/app/database/models/server/post.ts index b4b126cb20..a8d8cb67d3 100644 --- a/app/database/models/server/post.ts +++ b/app/database/models/server/post.ts @@ -8,20 +8,20 @@ import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; import {safeParseJSON} from '@utils/helpers'; -import type Channel from '@typings/database/models/servers/channel'; -import type Draft from '@typings/database/models/servers/draft'; -import type File from '@typings/database/models/servers/file'; -import type PostInThread from '@typings/database/models/servers/posts_in_thread'; -import type PostMetadata from '@typings/database/models/servers/post_metadata'; -import type Reaction from '@typings/database/models/servers/reaction'; -import type User from '@typings/database/models/servers/user'; +import type ChannelModel from '@typings/database/models/servers/channel'; +import type DraftModel from '@typings/database/models/servers/draft'; +import type FileModel from '@typings/database/models/servers/file'; +import type PostInThreadModel from '@typings/database/models/servers/posts_in_thread'; +import type PostMetadataModel from '@typings/database/models/servers/post_metadata'; +import type ReactionModel from '@typings/database/models/servers/reaction'; +import type UserModel from '@typings/database/models/servers/user'; const {CHANNEL, DRAFT, FILE, POST, POSTS_IN_THREAD, POST_METADATA, REACTION, USER} = MM_TABLES.SERVER; /** * The Post model is the building block of communication in the Mattermost app. */ -export default class Post extends Model { +export default class PostModel extends Model { /** table (name) : Post */ static table = POST; @@ -40,7 +40,7 @@ export default class Post extends Model { /** A POST can have multiple POSTS_IN_THREAD. (relationship is 1:N)*/ [POSTS_IN_THREAD]: {type: 'has_many', foreignKey: 'post_id'}, - /** A POST can have multiple POST_METADATA. (relationship is 1:N)*/ + /** A POST can have POST_METADATA. (relationship is 1:1)*/ [POST_METADATA]: {type: 'has_many', foreignKey: 'post_id'}, /** A POST can have multiple REACTION. (relationship is 1:N)*/ @@ -93,23 +93,23 @@ export default class Post extends Model { @json('props', safeParseJSON) props!: object; // A draft can be associated with this post for as long as this post is a parent post - @lazy draft = this.collections.get(DRAFT).query(Q.on(POST, 'id', this.id)) as Query; + @lazy draft = this.collections.get(DRAFT).query(Q.on(POST, 'id', this.id)) as Query; /** postsInThread: The thread to which this post is associated */ - @lazy postsInThread = this.collections.get(POSTS_IN_THREAD).query(Q.on(POST, 'id', this.id)) as Query; + @lazy postsInThread = this.collections.get(POSTS_IN_THREAD).query(Q.on(POST, 'id', this.id)) as Query; /** files: All the files associated with this Post */ - @children(FILE) files!: File[]; + @children(FILE) files!: FileModel[]; /** metadata: All the extra data associated with this Post */ - @children(POST_METADATA) metadata!: PostMetadata[]; + @children(POST_METADATA) metadata!: PostMetadataModel[]; /** reactions: All the reactions associated with this Post */ - @children(REACTION) reactions!: Reaction[]; + @children(REACTION) reactions!: ReactionModel[]; /** author: The author of this Post */ - @immutableRelation(USER, 'user_id') author!: Relation; + @immutableRelation(USER, 'user_id') author!: Relation; /** channel: The channel which is presenting this Post */ - @immutableRelation(CHANNEL, 'channel_id') channel!: Relation; + @immutableRelation(CHANNEL, 'channel_id') channel!: Relation; } diff --git a/app/database/models/server/post_metadata.ts b/app/database/models/server/post_metadata.ts index 9a5733f15b..163890e764 100644 --- a/app/database/models/server/post_metadata.ts +++ b/app/database/models/server/post_metadata.ts @@ -8,15 +8,14 @@ import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; import {safeParseJSON} from '@utils/helpers'; -import type {PostMetadataData, PostMetadataType} from '@typings/database/database'; -import type Post from '@typings/database/models/servers/post'; +import type PostModel from '@typings/database/models/servers/post'; const {POST, POST_METADATA} = MM_TABLES.SERVER; /** * PostMetadata provides additional information on a POST */ -export default class PostMetadata extends Model { +export default class PostMetadataModel extends Model { /** table (name) : PostMetadata */ static table = POST_METADATA; @@ -30,12 +29,9 @@ export default class PostMetadata extends Model { /** post_id : The foreign key of the parent POST model */ @field('post_id') postId!: string; - /** type : The type will work in tandem with the value present in the field 'data'. One 'type' for each kind of 'data' */ - @field('type') type!: PostMetadataType; - /** data : Different types of data ranging from embeds to images. */ - @json('data', safeParseJSON) data!: PostMetadataData; + @json('data', safeParseJSON) data!: PostMetadata; /** post: The record representing the POST parent. */ - @immutableRelation(POST, 'post_id') post!: Relation; + @immutableRelation(POST, 'post_id') post!: Relation; } diff --git a/app/database/models/server/posts_in_channel.ts b/app/database/models/server/posts_in_channel.ts index 1fdf80bbd1..e6c36e5282 100644 --- a/app/database/models/server/posts_in_channel.ts +++ b/app/database/models/server/posts_in_channel.ts @@ -6,7 +6,8 @@ import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; -import Channel from '@typings/database/models/servers/channel'; + +import type ChannelModel from '@typings/database/models/servers/channel'; const {CHANNEL, POSTS_IN_CHANNEL} = MM_TABLES.SERVER; @@ -14,7 +15,7 @@ const {CHANNEL, POSTS_IN_CHANNEL} = MM_TABLES.SERVER; * PostsInChannel model helps us to combine adjacent posts together without leaving * gaps in between for an efficient user reading experience of posts. */ -export default class PostsInChannel extends Model { +export default class PostsInChannelModel extends Model { /** table (name) : PostsInChannel */ static table = POSTS_IN_CHANNEL; @@ -35,5 +36,5 @@ export default class PostsInChannel extends Model { @field('latest') latest!: number; /** channel : The parent record of the channel for those posts */ - @immutableRelation(CHANNEL, 'channel_id') channel!: Relation; + @immutableRelation(CHANNEL, 'channel_id') channel!: Relation; } diff --git a/app/database/models/server/posts_in_thread.ts b/app/database/models/server/posts_in_thread.ts index bd4bc01b2f..df62bb98cb 100644 --- a/app/database/models/server/posts_in_thread.ts +++ b/app/database/models/server/posts_in_thread.ts @@ -6,7 +6,8 @@ import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; -import Post from '@typings/database/models/servers/post'; + +import type PostModel from '@typings/database/models/servers/post'; const {POST, POSTS_IN_THREAD} = MM_TABLES.SERVER; @@ -14,7 +15,7 @@ const {POST, POSTS_IN_THREAD} = MM_TABLES.SERVER; * PostsInThread model helps us to combine adjacent threads together without leaving * gaps in between for an efficient user reading experience for threads. */ -export default class PostsInThread extends Model { +export default class PostsInThreadModel extends Model { /** table (name) : PostsInThread */ static table = POSTS_IN_THREAD; @@ -35,5 +36,5 @@ export default class PostsInThread extends Model { @field('post_id') postId!: string; /** post : The related record to the parent Post model */ - @immutableRelation(POST, 'post_id') post!: Relation; + @immutableRelation(POST, 'post_id') post!: Relation; } diff --git a/app/database/models/server/preference.ts b/app/database/models/server/preference.ts index 466278c3c4..03f14dade7 100644 --- a/app/database/models/server/preference.ts +++ b/app/database/models/server/preference.ts @@ -6,7 +6,8 @@ import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; -import User from '@typings/database/models/servers/user'; + +import type UserModel from '@typings/database/models/servers/user'; const {PREFERENCE, USER} = MM_TABLES.SERVER; @@ -14,7 +15,7 @@ const {PREFERENCE, USER} = MM_TABLES.SERVER; * The Preference model hold information about the user's preference in the app. * This includes settings about the account, the themes, etc. */ -export default class Preference extends Model { +export default class PreferenceModel extends Model { /** table (name) : Preference */ static table = PREFERENCE; @@ -38,5 +39,5 @@ export default class Preference extends Model { @field('value') value!: string; /** user : The related record to the parent User model */ - @immutableRelation(USER, 'user_id') user!: Relation; + @immutableRelation(USER, 'user_id') user!: Relation; } diff --git a/app/database/models/server/reaction.ts b/app/database/models/server/reaction.ts index 37fcc79f6c..d9b3ce2267 100644 --- a/app/database/models/server/reaction.ts +++ b/app/database/models/server/reaction.ts @@ -6,15 +6,16 @@ import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; -import Post from '@typings/database/models/servers/post'; -import User from '@typings/database/models/servers/user'; + +import type PostModel from '@typings/database/models/servers/post'; +import type UserModel from '@typings/database/models/servers/user'; const {POST, REACTION, USER} = MM_TABLES.SERVER; /** * The Reaction Model is used to present the reactions a user had on a particular post */ -export default class Reaction extends Model { +export default class ReactionModel extends Model { /** table (name) : Reaction */ static table = REACTION; @@ -41,8 +42,8 @@ export default class Reaction extends Model { @field('user_id') userId!: string; /** user : The related record to the User model */ - @immutableRelation(USER, 'user_id') user!: Relation; + @immutableRelation(USER, 'user_id') user!: Relation; /** post : The related record to the Post model */ - @immutableRelation(POST, 'post_id') post!: Relation; + @immutableRelation(POST, 'post_id') post!: Relation; } diff --git a/app/database/models/server/role.ts b/app/database/models/server/role.ts index 90b7e72cd5..094e4d63cb 100644 --- a/app/database/models/server/role.ts +++ b/app/database/models/server/role.ts @@ -10,7 +10,7 @@ import {safeParseJSON} from '@utils/helpers'; const {ROLE} = MM_TABLES.SERVER; /** The Role model will describe the set of permissions for each role */ -export default class Role extends Model { +export default class RoleModel extends Model { /** table (name) : Role */ static table = ROLE; diff --git a/app/database/models/server/slash_command.ts b/app/database/models/server/slash_command.ts index 120c8b1936..3fcf85801f 100644 --- a/app/database/models/server/slash_command.ts +++ b/app/database/models/server/slash_command.ts @@ -6,14 +6,15 @@ import {field, immutableRelation} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; -import Team from '@typings/database/models/servers/team'; + +import type TeamModel from '@typings/database/models/servers/team'; const {SLASH_COMMAND, TEAM} = MM_TABLES.SERVER; /** * The SlashCommand model describes the commands of the various commands available in each team. */ -export default class SlashCommand extends Model { +export default class SlashCommandModel extends Model { /** table (name) : SlashCommand */ static table = SLASH_COMMAND; @@ -52,5 +53,5 @@ export default class SlashCommand extends Model { @field('update_at') updateAt!: number; /** team : The related parent TEAM record */ - @immutableRelation(TEAM, 'team_id') team!: Relation; + @immutableRelation(TEAM, 'team_id') team!: Relation; } diff --git a/app/database/models/server/system.ts b/app/database/models/server/system.ts index 78fccddea0..a5de14a75b 100644 --- a/app/database/models/server/system.ts +++ b/app/database/models/server/system.ts @@ -14,7 +14,7 @@ const {SYSTEM} = MM_TABLES.SERVER; * will mostly hold configuration information about the client, the licences and some * custom data (e.g. recent emoji used) */ -export default class System extends Model { +export default class SystemModel extends Model { /** table (name) : System */ static table = SYSTEM; diff --git a/app/database/models/server/team.ts b/app/database/models/server/team.ts index eb385a59ef..385cc5fa98 100644 --- a/app/database/models/server/team.ts +++ b/app/database/models/server/team.ts @@ -6,13 +6,14 @@ import {children, field, lazy} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; -import Channel from '@typings/database/models/servers/channel'; -import GroupsInTeam from '@typings/database/models/servers/groups_in_team'; -import MyTeam from '@typings/database/models/servers/my_team'; -import SlashCommand from '@typings/database/models/servers/slash_command'; -import TeamChannelHistory from '@typings/database/models/servers/team_channel_history'; -import TeamMembership from '@typings/database/models/servers/team_membership'; -import TeamSearchHistory from '@typings/database/models/servers/team_search_history'; + +import type ChannelModel from '@typings/database/models/servers/channel'; +import type GroupsInTeamModel from '@typings/database/models/servers/groups_in_team'; +import type MyTeamModel from '@typings/database/models/servers/my_team'; +import type SlashCommandModel from '@typings/database/models/servers/slash_command'; +import type TeamChannelHistoryModel from '@typings/database/models/servers/team_channel_history'; +import type TeamMembershipModel from '@typings/database/models/servers/team_membership'; +import type TeamSearchHistoryModel from '@typings/database/models/servers/team_search_history'; const { CHANNEL, @@ -28,7 +29,7 @@ const { /** * A Team houses and enables communication to happen across channels and users. */ -export default class Team extends Model { +export default class TeamModel extends Model { /** table (name) : Team */ static table = TEAM; @@ -85,23 +86,23 @@ export default class Team extends Model { @field('allowed_domains') allowedDomains!: string; /** channels : All the channels associated with this team */ - @children(CHANNEL) channels!: Channel[]; + @children(CHANNEL) channels!: ChannelModel[]; /** groupsInTeam : All the groups associated with this team */ - @children(GROUPS_IN_TEAM) groupsInTeam!: GroupsInTeam[]; + @children(GROUPS_IN_TEAM) groupsInTeam!: GroupsInTeamModel[]; /** myTeam : Retrieves additional information about the team that this user is possibly part of. This query might yield no result if the user isn't part of a team. */ - @lazy myTeam = this.collections.get(MY_TEAM).query(Q.on(TEAM, 'id', this.id)) as Query; + @lazy myTeam = this.collections.get(MY_TEAM).query(Q.on(TEAM, 'id', this.id)) as Query; /** slashCommands : All the slash commands associated with this team */ - @children(SLASH_COMMAND) slashCommands!: SlashCommand[]; + @children(SLASH_COMMAND) slashCommands!: SlashCommandModel[]; /** teamChannelHistory : A history of the channels in this team that has been visited, ordered by the most recent and capped to the last 5 */ - @lazy teamChannelHistory = this.collections.get(TEAM_CHANNEL_HISTORY).query(Q.on(TEAM, 'id', this.id)) as Query; + @lazy teamChannelHistory = this.collections.get(TEAM_CHANNEL_HISTORY).query(Q.on(TEAM, 'id', this.id)) as Query; /** members : All the users associated with this team */ - @children(TEAM_MEMBERSHIP) members!: TeamMembership[]; + @children(TEAM_MEMBERSHIP) members!: TeamMembershipModel[]; /** teamSearchHistories : All the searches performed on this team */ - @children(TEAM_SEARCH_HISTORY) teamSearchHistories!: TeamSearchHistory[]; + @children(TEAM_SEARCH_HISTORY) teamSearchHistories!: TeamSearchHistoryModel[]; } diff --git a/app/database/models/server/team_channel_history.ts b/app/database/models/server/team_channel_history.ts index 956af80f90..2a56a7be13 100644 --- a/app/database/models/server/team_channel_history.ts +++ b/app/database/models/server/team_channel_history.ts @@ -8,7 +8,7 @@ import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; import {safeParseJSON} from '@utils/helpers'; -import type Team from '@typings/database/models/servers/team'; +import type TeamModel from '@typings/database/models/servers/team'; const {TEAM, TEAM_CHANNEL_HISTORY} = MM_TABLES.SERVER; @@ -16,7 +16,7 @@ const {TEAM, TEAM_CHANNEL_HISTORY} = MM_TABLES.SERVER; * The TeamChannelHistory model helps keeping track of the last channel visited * by the user. */ -export default class TeamChannelHistory extends Model { +export default class TeamChannelHistoryModel extends Model { /** table (name) : TeamChannelHistory */ static table = TEAM_CHANNEL_HISTORY; @@ -34,5 +34,5 @@ export default class TeamChannelHistory extends Model { @json('channel_ids', safeParseJSON) channelIds!: string[]; /** team : The related record from the parent Team model */ - @immutableRelation(TEAM, 'team_id') team!: Relation; + @immutableRelation(TEAM, 'team_id') team!: Relation; } diff --git a/app/database/models/server/team_membership.ts b/app/database/models/server/team_membership.ts index 680e85379b..a6c6dabb70 100644 --- a/app/database/models/server/team_membership.ts +++ b/app/database/models/server/team_membership.ts @@ -6,8 +6,9 @@ import {field, immutableRelation, lazy} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; -import Team from '@typings/database/models/servers/team'; -import User from '@typings/database/models/servers/user'; + +import type TeamModel from '@typings/database/models/servers/team'; +import type UserModel from '@typings/database/models/servers/user'; const {TEAM, TEAM_MEMBERSHIP, USER} = MM_TABLES.SERVER; @@ -15,7 +16,7 @@ const {TEAM, TEAM_MEMBERSHIP, USER} = MM_TABLES.SERVER; * The TeamMembership model represents the 'association table' where many teams have users and many users are in * teams (relationship type N:N) */ -export default class TeamMembership extends Model { +export default class TeamMembershipModel extends Model { /** table (name) : TeamMembership */ static table = TEAM_MEMBERSHIP; @@ -36,18 +37,18 @@ export default class TeamMembership extends Model { @field('user_id') userId!: string; /** memberUser: The related user in the team */ - @immutableRelation(USER, 'user_id') memberUser!: Relation; + @immutableRelation(USER, 'user_id') memberUser!: Relation; /** memberTeam : The related team of users */ - @immutableRelation(TEAM, 'team_id') memberTeam!: Relation; + @immutableRelation(TEAM, 'team_id') memberTeam!: Relation; /** * getAllTeamsForUser - Retrieves all the teams that the user is part of */ - @lazy getAllTeamsForUser = this.collections.get(TEAM).query(Q.on(USER, 'id', this.userId)) as Query; + @lazy getAllTeamsForUser = this.collections.get(TEAM).query(Q.on(USER, 'id', this.userId)) as Query; /** * getAllUsersInTeam - Retrieves all the users who are part of this team */ - @lazy getAllUsersInTeam = this.collections.get(USER).query(Q.on(TEAM, 'id', this.teamId)) as Query; + @lazy getAllUsersInTeam = this.collections.get(USER).query(Q.on(TEAM, 'id', this.teamId)) as Query; } diff --git a/app/database/models/server/team_search_history.ts b/app/database/models/server/team_search_history.ts index 69eab408b5..bd9bad1b5e 100644 --- a/app/database/models/server/team_search_history.ts +++ b/app/database/models/server/team_search_history.ts @@ -6,7 +6,8 @@ import {field, immutableRelation, text} from '@nozbe/watermelondb/decorators'; import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; -import Team from '@typings/database/models/servers/team'; + +import type TeamModel from '@typings/database/models/servers/team'; const {TEAM, TEAM_SEARCH_HISTORY} = MM_TABLES.SERVER; @@ -14,7 +15,7 @@ const {TEAM, TEAM_SEARCH_HISTORY} = MM_TABLES.SERVER; * The TeamSearchHistory model holds the term searched within a team. The searches are performed * at team level in the app. */ -export default class TeamSearchHistory extends Model { +export default class TeamSearchHistoryModel extends Model { /** table (name) : TeamSearchHistory */ static table = TEAM_SEARCH_HISTORY; @@ -38,5 +39,5 @@ export default class TeamSearchHistory extends Model { @text('term') term!: string; /** team : The related record to the parent team model */ - @immutableRelation(TEAM, 'team_id') team!: Relation; + @immutableRelation(TEAM, 'team_id') team!: Relation; } diff --git a/app/database/models/server/terms_of_service.ts b/app/database/models/server/terms_of_service.ts index 3c977da7cb..6cd1f33b1f 100644 --- a/app/database/models/server/terms_of_service.ts +++ b/app/database/models/server/terms_of_service.ts @@ -11,7 +11,7 @@ const {TERMS_OF_SERVICE} = MM_TABLES.SERVER; /** * The model for Terms of Service */ -export default class TermsOfService extends Model { +export default class TermsOfServiceModel extends Model { /** table (name) : TermsOfService */ static table = TERMS_OF_SERVICE; diff --git a/app/database/models/server/user.ts b/app/database/models/server/user.ts index 616bd20389..dcd44dd9aa 100644 --- a/app/database/models/server/user.ts +++ b/app/database/models/server/user.ts @@ -7,13 +7,13 @@ import Model, {Associations} from '@nozbe/watermelondb/Model'; import {MM_TABLES} from '@constants/database'; import {safeParseJSON} from '@utils/helpers'; -import type Channel from '@typings/database/models/servers/channel'; -import type ChannelMembership from '@typings/database/models/servers/channel_membership'; -import type GroupMembership from '@typings/database/models/servers/group_membership'; -import type Post from '@typings/database/models/servers/post'; -import type Preference from '@typings/database/models/servers/preference'; -import type Reaction from '@typings/database/models/servers/reaction'; -import type TeamMembership from '@typings/database/models/servers/team_membership'; +import type ChannelModel from '@typings/database/models/servers/channel'; +import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership'; +import type GroupMembershipModel from '@typings/database/models/servers/group_membership'; +import type PostModel from '@typings/database/models/servers/post'; +import type PreferenceModel from '@typings/database/models/servers/preference'; +import type ReactionModel from '@typings/database/models/servers/reaction'; +import type TeamMembershipModel from '@typings/database/models/servers/team_membership'; const { CHANNEL, @@ -30,7 +30,7 @@ const { * The User model represents the 'USER' table and its relationship to other * shareholders in the app. */ -export default class User extends Model { +export default class UserModel extends Model { /** table (name) : User */ static table = USER; @@ -105,34 +105,34 @@ export default class User extends Model { @field('username') username!: string; /** notify_props : Notification preferences/configurations */ - @json('notify_props', safeParseJSON) notifyProps!: NotifyProps; + @json('notify_props', safeParseJSON) notifyProps!: UserNotifyProps | null; /** props : Custom objects ( e.g. custom status) can be stored in there. Its type definition is known as * 'excess property check' in Typescript land. We keep using it till we build up the final shape of this object. */ - @json('props', safeParseJSON) props!: UserProps; + @json('props', safeParseJSON) props!: UserProps | null; /** timezone : The timezone for this user */ - @json('timezone', safeParseJSON) timezone!: Timezone; + @json('timezone', safeParseJSON) timezone!: UserTimezone | null; /** channelsCreated : All the channels that this user created */ - @children(CHANNEL) channelsCreated!: Channel[]; + @children(CHANNEL) channelsCreated!: ChannelModel[]; /** channels : All the channels that this user is part of */ - @children(CHANNEL_MEMBERSHIP) channels!: ChannelMembership[]; + @children(CHANNEL_MEMBERSHIP) channels!: ChannelMembershipModel[]; /** groups : All the groups that this user is part of */ - @children(GROUP_MEMBERSHIP) groups!: GroupMembership[]; + @children(GROUP_MEMBERSHIP) groups!: GroupMembershipModel[]; /** posts : All the posts that this user has written*/ - @children(POST) posts!: Post[]; + @children(POST) posts!: PostModel[]; /** preferences : All user preferences */ - @children(PREFERENCE) preferences!: Preference[]; + @children(PREFERENCE) preferences!: PreferenceModel[]; /** reactions : All the reactions to posts that this user had */ - @children(REACTION) reactions!: Reaction[]; + @children(REACTION) reactions!: ReactionModel[]; /** teams : All the team that this user is part of */ - @children(TEAM_MEMBERSHIP) teams!: TeamMembership[]; + @children(TEAM_MEMBERSHIP) teams!: TeamMembershipModel[]; } diff --git a/app/database/operator/app_data_operator/comparator/index.ts b/app/database/operator/app_data_operator/comparator/index.ts index a5ec6a693f..35aaf60421 100644 --- a/app/database/operator/app_data_operator/comparator/index.ts +++ b/app/database/operator/app_data_operator/comparator/index.ts @@ -1,19 +1,13 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import Info from '@typings/database/models/app/info'; -import {RawInfo, RawGlobal, RawServers} from '@typings/database/database'; -import Global from '@typings/database/models/app/global'; -import Servers from '@typings/database/models/app/servers'; +import type InfoModel from '@typings/database/models/app/info'; +import type GlobalModel from '@typings/database/models/app/global'; -export const isRecordInfoEqualToRaw = (record: Info, raw: RawInfo) => { +export const isRecordInfoEqualToRaw = (record: InfoModel, raw: AppInfo) => { return (raw.build_number === record.buildNumber && raw.version_number === record.versionNumber); }; -export const isRecordGlobalEqualToRaw = (record: Global, raw: RawGlobal) => { +export const isRecordGlobalEqualToRaw = (record: GlobalModel, raw: IdValue) => { return raw.id === record.id && raw.value === record.value; }; - -export const isRecordServerEqualToRaw = (record: Servers, raw: RawServers) => { - return raw.url === record.url && raw.db_path === record.dbPath; -}; diff --git a/app/database/operator/app_data_operator/index.test.ts b/app/database/operator/app_data_operator/index.test.ts index 0e89215100..323736dfdd 100644 --- a/app/database/operator/app_data_operator/index.test.ts +++ b/app/database/operator/app_data_operator/index.test.ts @@ -5,14 +5,11 @@ import DatabaseManager from '@database/manager'; import { isRecordInfoEqualToRaw, isRecordGlobalEqualToRaw, - isRecordServerEqualToRaw, } from '@database/operator/app_data_operator/comparator'; import { transformInfoRecord, transformGlobalRecord, - transformServersRecord, } from '@database/operator/app_data_operator/transformers'; -import {RawGlobal, RawServers} from '@typings/database/database'; describe('** APP DATA OPERATOR **', () => { beforeAll(async () => { @@ -72,7 +69,7 @@ describe('** APP DATA OPERATOR **', () => { expect(appOperator).toBeTruthy(); const spyOnHandleRecords = jest.spyOn(appOperator as any, 'handleRecords'); - const global: RawGlobal[] = [{id: 'global-1-name', value: 'global-1-value'}]; + const global: IdValue[] = [{id: 'global-1-name', value: 'global-1-value'}]; await appOperator?.handleGlobal({ global, @@ -88,49 +85,4 @@ describe('** APP DATA OPERATOR **', () => { prepareRecordsOnly: false, }); }); - - it('=> HandleServers: should write to SERVERS table', async () => { - const appDatabase = DatabaseManager.appDatabase?.database; - const appOperator = DatabaseManager.appDatabase?.operator; - expect(appDatabase).toBeTruthy(); - expect(appOperator).toBeTruthy(); - - const spyOnHandleRecords = jest.spyOn(appOperator as any, 'handleRecords'); - - const servers: RawServers[] = [ - { - db_path: 'server.db', - display_name: 'community', - mention_count: 0, - unread_count: 0, - url: 'https://community.mattermost.com', - isSecured: true, - lastActiveAt: 1623926359, - }, - ]; - - await appOperator?.handleServers({ - servers, - prepareRecordsOnly: false, - }); - - expect(spyOnHandleRecords).toHaveBeenCalledWith({ - fieldName: 'url', - transformer: transformServersRecord, - findMatchingRecordBy: isRecordServerEqualToRaw, - createOrUpdateRawValues: [ - { - db_path: 'server.db', - display_name: 'community', - mention_count: 0, - unread_count: 0, - url: 'https://community.mattermost.com', - isSecured: true, - lastActiveAt: 1623926359, - }, - ], - tableName: 'Servers', - prepareRecordsOnly: false, - }); - }); }); diff --git a/app/database/operator/app_data_operator/index.ts b/app/database/operator/app_data_operator/index.ts index bab0e49ba7..84ae4a71ab 100644 --- a/app/database/operator/app_data_operator/index.ts +++ b/app/database/operator/app_data_operator/index.ts @@ -3,35 +3,24 @@ import {MM_TABLES} from '@constants/database'; import DataOperatorException from '@database/exceptions/data_operator_exception'; -import { - isRecordInfoEqualToRaw, - isRecordGlobalEqualToRaw, - isRecordServerEqualToRaw, -} from '@database/operator/app_data_operator/comparator'; -import { - transformInfoRecord, - transformGlobalRecord, - transformServersRecord, -} from '@database/operator/app_data_operator/transformers'; +import {isRecordInfoEqualToRaw, isRecordGlobalEqualToRaw} from '@database/operator/app_data_operator/comparator'; +import {transformInfoRecord, transformGlobalRecord} from '@database/operator/app_data_operator/transformers'; import BaseDataOperator from '@database/operator/base_data_operator'; import {getUniqueRawsBy} from '@database/operator/utils/general'; -import { - HandleInfoArgs, - HandleGlobalArgs, - HandleServersArgs, -} from '@typings/database/database'; -const {APP: {INFO, GLOBAL, SERVERS}} = MM_TABLES; +import type {HandleInfoArgs, HandleGlobalArgs} from '@typings/database/database'; + +const {APP: {INFO, GLOBAL}} = MM_TABLES; export default class AppDataOperator extends BaseDataOperator { - handleInfo = async ({info, prepareRecordsOnly = true}: HandleInfoArgs) => { + handleInfo = ({info, prepareRecordsOnly = true}: HandleInfoArgs) => { if (!info.length) { throw new DataOperatorException( 'An empty "values" array has been passed to the handleInfo', ); } - const records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'version_number', findMatchingRecordBy: isRecordInfoEqualToRaw, transformer: transformInfoRecord, @@ -39,8 +28,6 @@ export default class AppDataOperator extends BaseDataOperator { createOrUpdateRawValues: getUniqueRawsBy({raws: info, key: 'version_number'}), tableName: INFO, }); - - return records; } handleGlobal = async ({global, prepareRecordsOnly = true}: HandleGlobalArgs) => { @@ -50,7 +37,7 @@ export default class AppDataOperator extends BaseDataOperator { ); } - const records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'id', findMatchingRecordBy: isRecordGlobalEqualToRaw, transformer: transformGlobalRecord, @@ -58,26 +45,5 @@ export default class AppDataOperator extends BaseDataOperator { createOrUpdateRawValues: getUniqueRawsBy({raws: global, key: 'id'}), tableName: GLOBAL, }); - - return records; - } - - handleServers = async ({servers, prepareRecordsOnly = true}: HandleServersArgs) => { - if (!servers.length) { - throw new DataOperatorException( - 'An empty "values" array has been passed to the handleServers', - ); - } - - const records = await this.handleRecords({ - fieldName: 'url', - findMatchingRecordBy: isRecordServerEqualToRaw, - transformer: transformServersRecord, - prepareRecordsOnly, - createOrUpdateRawValues: getUniqueRawsBy({raws: servers, key: 'display_name'}), - tableName: SERVERS, - }); - - return records; } } diff --git a/app/database/operator/app_data_operator/transformers/index.ts b/app/database/operator/app_data_operator/transformers/index.ts index bab077eded..3e86234960 100644 --- a/app/database/operator/app_data_operator/transformers/index.ts +++ b/app/database/operator/app_data_operator/transformers/index.ts @@ -3,13 +3,15 @@ import {MM_TABLES} from '@constants/database'; import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers'; -import Info from '@typings/database/models/app/info'; -import {TransformerArgs, RawInfo, RawGlobal, RawServers} from '@typings/database/database'; -import {OperationType} from '@typings/database/enums'; -import Global from '@typings/database/models/app/global'; -import Servers from '@typings/database/models/app/servers'; -const {INFO, GLOBAL, SERVERS} = MM_TABLES.APP; +import type {Model} from '@nozbe/watermelondb'; + +import type InfoModel from '@typings/database/models/app/info'; +import type {TransformerArgs} from '@typings/database/database'; +import {OperationType} from '@typings/database/enums'; +import type GlobalModel from '@typings/database/models/app/global'; + +const {INFO, GLOBAL} = MM_TABLES.APP; /** * transformInfoRecord: Prepares a record of the APP database 'Info' table for update or create actions. @@ -18,12 +20,12 @@ const {INFO, GLOBAL, SERVERS} = MM_TABLES.APP; * @param {RecordPair} operator.value * @returns {Promise} */ -export const transformInfoRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawInfo; - const record = value.record as Info; +export const transformInfoRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as AppInfo; + const record = value.record as InfoModel; const isCreateAction = action === OperationType.CREATE; - const fieldsMapper = (app: Info) => { + const fieldsMapper = (app: InfoModel) => { app._raw.id = isCreateAction ? app.id : record.id; app.buildNumber = raw?.build_number; app.createdAt = raw?.created_at; @@ -46,10 +48,10 @@ export const transformInfoRecord = ({action, database, value}: TransformerArgs) * @param {RecordPair} operator.value * @returns {Promise} */ -export const transformGlobalRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawGlobal; +export const transformGlobalRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as IdValue; - const fieldsMapper = (global: Global) => { + const fieldsMapper = (global: GlobalModel) => { global._raw.id = raw?.id; global.value = raw?.value; }; @@ -63,34 +65,3 @@ export const transformGlobalRecord = ({action, database, value}: TransformerArgs }); }; -/** - * transformServersRecord: Prepares a record of the APP database 'Servers' table for update or create actions. - * @param {TransformerArgs} operator - * @param {Database} operator.database - * @param {RecordPair} operator.value - * @returns {Promise} - */ -export const transformServersRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawServers; - const record = value.record as Servers; - const isCreateAction = action === OperationType.CREATE; - - const fieldsMapper = (servers: Servers) => { - servers._raw.id = isCreateAction ? servers.id : record.id; - servers.dbPath = raw?.db_path; - servers.displayName = raw?.display_name; - servers.mentionCount = raw?.mention_count; - servers.unreadCount = raw?.unread_count; - servers.url = raw?.url; - servers.isSecured = raw?.isSecured; - servers.lastActiveAt = raw?.lastActiveAt; - }; - - return prepareBaseRecord({ - action, - database, - tableName: SERVERS, - value, - fieldsMapper, - }); -}; diff --git a/app/database/operator/app_data_operator/transformers/test.ts b/app/database/operator/app_data_operator/transformers/test.ts index f29ef8f193..712780bb01 100644 --- a/app/database/operator/app_data_operator/transformers/test.ts +++ b/app/database/operator/app_data_operator/transformers/test.ts @@ -5,7 +5,6 @@ import DatabaseManager from '@database/manager'; import { transformInfoRecord, transformGlobalRecord, - transformServersRecord, } from '@database/operator/app_data_operator/transformers/index'; import {OperationType} from '@typings/database/enums'; @@ -14,33 +13,6 @@ describe('** APP DATA TRANSFORMER **', () => { await DatabaseManager.init([]); }); - it('=> transformServersRecord: should return an array of type Servers', async () => { - expect.assertions(3); - - const database = DatabaseManager.appDatabase?.database; - expect(database).toBeTruthy(); - - const preparedRecords = await transformServersRecord({ - action: OperationType.CREATE, - database: database!, - value: { - record: undefined, - raw: { - db_path: 'mm-server', - display_name: 's-displayName', - mention_count: 1, - unread_count: 0, - url: 'https://community.mattermost.com', - isSecured: true, - lastActiveAt: 1623926359, - }, - }, - }); - - expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('Servers'); - }); - it('=> transformInfoRecord: should return an array of type Info', async () => { expect.assertions(3); @@ -61,7 +33,7 @@ describe('** APP DATA TRANSFORMER **', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('Info'); + expect(preparedRecords!.collection.modelClass.name).toBe('InfoModel'); }); it('=> transformGlobalRecord: should return an array of type Global', async () => { @@ -80,6 +52,6 @@ describe('** APP DATA TRANSFORMER **', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('Global'); + expect(preparedRecords!.collection.modelClass.name).toBe('GlobalModel'); }); }); diff --git a/app/database/operator/base_data_operator/index.ts b/app/database/operator/base_data_operator/index.ts index 39a51c9e9f..73be1f29b9 100644 --- a/app/database/operator/base_data_operator/index.ts +++ b/app/database/operator/base_data_operator/index.ts @@ -17,7 +17,6 @@ import type { OperationArgs, ProcessRecordResults, ProcessRecordsArgs, - RawValue, RecordPair, } from '@typings/database/database'; import {OperationType} from '@typings/database/enums'; @@ -123,7 +122,7 @@ export default class BaseDataOperator { * @throws {DataOperatorException} * @returns {Promise} */ - prepareRecords = async ({tableName, createRaws, deleteRaws, updateRaws, transformer}: OperationArgs) => { + prepareRecords = async ({tableName, createRaws, deleteRaws, updateRaws, transformer}: OperationArgs): Promise => { if (!this.database) { throw new DataOperatorException('Database not defined'); } @@ -180,7 +179,7 @@ export default class BaseDataOperator { * @throws {DataOperatorException} * @returns {Promise} */ - batchRecords = async (models: Model[]) => { + batchRecords = async (models: Model[]): Promise => { try { if (models.length > 0) { await this.database.action(async () => { @@ -203,7 +202,7 @@ export default class BaseDataOperator { * @param {string} handleRecordsArgs.tableName * @returns {Promise} */ - handleRecords = async ({findMatchingRecordBy, fieldName, transformer, createOrUpdateRawValues, deleteRawValues = [], tableName, prepareRecordsOnly = true}: HandleRecordsArgs) => { + handleRecords = async ({findMatchingRecordBy, fieldName, transformer, createOrUpdateRawValues, deleteRawValues = [], tableName, prepareRecordsOnly = true}: HandleRecordsArgs): Promise => { if (!createOrUpdateRawValues.length) { throw new DataOperatorException( `An empty "rawValues" array has been passed to the handleRecords method for tableName ${tableName}`, diff --git a/app/database/operator/server_data_operator/comparators/index.ts b/app/database/operator/server_data_operator/comparators/index.ts index b33e4951ea..379320ba0f 100644 --- a/app/database/operator/server_data_operator/comparators/index.ts +++ b/app/database/operator/server_data_operator/comparators/index.ts @@ -1,54 +1,29 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import Channel from '@typings/database/models/servers/channel'; -import ChannelInfo from '@typings/database/models/servers/channel_info'; -import ChannelMembership from '@typings/database/models/servers/channel_membership'; -import CustomEmoji from '@typings/database/models/servers/custom_emoji'; -import { - RawChannel, - RawChannelInfo, - RawChannelMembership, - RawCustomEmoji, - RawDraft, - RawGroup, - RawGroupMembership, - RawGroupsInChannel, - RawGroupsInTeam, - RawMyChannel, - RawMyChannelSettings, - RawMyTeam, - RawPost, - RawPreference, - RawRole, - RawSlashCommand, - RawSystem, - RawTeam, - RawTeamChannelHistory, - RawTeamMembership, - RawTeamSearchHistory, - RawTermsOfService, - RawUser, -} from '@typings/database/database'; -import Draft from '@typings/database/models/servers/draft'; -import Group from '@typings/database/models/servers/group'; -import GroupMembership from '@typings/database/models/servers/group_membership'; -import GroupsInChannel from '@typings/database/models/servers/groups_in_channel'; -import GroupsInTeam from '@typings/database/models/servers/groups_in_team'; -import MyChannel from '@typings/database/models/servers/my_channel'; -import MyChannelSettings from '@typings/database/models/servers/my_channel_settings'; -import MyTeam from '@typings/database/models/servers/my_team'; -import Post from '@typings/database/models/servers/post'; -import Preference from '@typings/database/models/servers/preference'; -import Role from '@typings/database/models/servers/role'; -import SlashCommand from '@typings/database/models/servers/slash_command'; -import System from '@typings/database/models/servers/system'; -import Team from '@typings/database/models/servers/team'; -import TeamChannelHistory from '@typings/database/models/servers/team_channel_history'; -import TeamMembership from '@typings/database/models/servers/team_membership'; -import TeamSearchHistory from '@typings/database/models/servers/team_search_history'; -import TermsOfService from '@typings/database/models/servers/terms_of_service'; -import User from '@typings/database/models/servers/user'; +import type ChannelModel from '@typings/database/models/servers/channel'; +import type ChannelInfoModel from '@typings/database/models/servers/channel_info'; +import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership'; +import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji'; +import type DraftModel from '@typings/database/models/servers/draft'; +import type GroupModel from '@typings/database/models/servers/group'; +import type GroupMembershipModel from '@typings/database/models/servers/group_membership'; +import type GroupsInChannelModel from '@typings/database/models/servers/groups_in_channel'; +import type GroupsInTeamModel from '@typings/database/models/servers/groups_in_team'; +import type MyChannelModel from '@typings/database/models/servers/my_channel'; +import type MyChannelSettingsModel from '@typings/database/models/servers/my_channel_settings'; +import type MyTeamModel from '@typings/database/models/servers/my_team'; +import type PostModel from '@typings/database/models/servers/post'; +import type PreferenceModel from '@typings/database/models/servers/preference'; +import type RoleModel from '@typings/database/models/servers/role'; +import type SlashCommandModel from '@typings/database/models/servers/slash_command'; +import type SystemModel from '@typings/database/models/servers/system'; +import type TeamModel from '@typings/database/models/servers/team'; +import type TeamChannelHistoryModel from '@typings/database/models/servers/team_channel_history'; +import type TeamMembershipModel from '@typings/database/models/servers/team_membership'; +import type TeamSearchHistoryModel from '@typings/database/models/servers/team_search_history'; +import type TermsOfServiceModel from '@typings/database/models/servers/terms_of_service'; +import type UserModel from '@typings/database/models/servers/user'; /** * This file contains all the comparators that are used by the handlers to find out which records to truly update and @@ -57,31 +32,31 @@ import User from '@typings/database/models/servers/user'; * 'record' and the 'raw' */ -export const isRecordRoleEqualToRaw = (record: Role, raw: RawRole) => { +export const isRecordRoleEqualToRaw = (record: RoleModel, raw: Role) => { return raw.id === record.id; }; -export const isRecordSystemEqualToRaw = (record: System, raw: RawSystem) => { +export const isRecordSystemEqualToRaw = (record: SystemModel, raw: IdValue) => { return raw.id === record.id; }; -export const isRecordTermsOfServiceEqualToRaw = (record: TermsOfService, raw: RawTermsOfService) => { +export const isRecordTermsOfServiceEqualToRaw = (record: TermsOfServiceModel, raw: TermsOfService) => { return raw.id === record.id; }; -export const isRecordDraftEqualToRaw = (record: Draft, raw: RawDraft) => { +export const isRecordDraftEqualToRaw = (record: DraftModel, raw: Draft) => { return raw.channel_id === record.channelId; }; -export const isRecordPostEqualToRaw = (record: Post, raw: RawPost) => { +export const isRecordPostEqualToRaw = (record: PostModel, raw: Post) => { return raw.id === record.id; }; -export const isRecordUserEqualToRaw = (record: User, raw: RawUser) => { +export const isRecordUserEqualToRaw = (record: UserModel, raw: UserProfile) => { return raw.id === record.id; }; -export const isRecordPreferenceEqualToRaw = (record: Preference, raw: RawPreference) => { +export const isRecordPreferenceEqualToRaw = (record: PreferenceModel, raw: PreferenceType) => { return ( raw.category === record.category && raw.name === record.name && @@ -89,66 +64,66 @@ export const isRecordPreferenceEqualToRaw = (record: Preference, raw: RawPrefere ); }; -export const isRecordTeamMembershipEqualToRaw = (record: TeamMembership, raw: RawTeamMembership) => { +export const isRecordTeamMembershipEqualToRaw = (record: TeamMembershipModel, raw: TeamMembership) => { return raw.team_id === record.teamId && raw.user_id === record.userId; }; -export const isRecordCustomEmojiEqualToRaw = (record: CustomEmoji, raw: RawCustomEmoji) => { +export const isRecordCustomEmojiEqualToRaw = (record: CustomEmojiModel, raw: CustomEmoji) => { return raw.id === record.id; }; -export const isRecordGroupMembershipEqualToRaw = (record: GroupMembership, raw: RawGroupMembership) => { +export const isRecordGroupMembershipEqualToRaw = (record: GroupMembershipModel, raw: GroupMembership) => { return raw.user_id === record.userId && raw.group_id === record.groupId; }; -export const isRecordChannelMembershipEqualToRaw = (record: ChannelMembership, raw: RawChannelMembership) => { +export const isRecordChannelMembershipEqualToRaw = (record: ChannelMembershipModel, raw: ChannelMembership) => { return raw.user_id === record.userId && raw.channel_id === record.channelId; }; -export const isRecordGroupEqualToRaw = (record: Group, raw: RawGroup) => { +export const isRecordGroupEqualToRaw = (record: GroupModel, raw: Group) => { return raw.id === record.id; }; -export const isRecordGroupsInTeamEqualToRaw = (record: GroupsInTeam, raw: RawGroupsInTeam) => { +export const isRecordGroupsInTeamEqualToRaw = (record: GroupsInTeamModel, raw: GroupTeam) => { return raw.team_id === record.teamId && raw.group_id === record.groupId; }; -export const isRecordGroupsInChannelEqualToRaw = (record: GroupsInChannel, raw: RawGroupsInChannel) => { +export const isRecordGroupsInChannelEqualToRaw = (record: GroupsInChannelModel, raw: GroupChannel) => { return raw.channel_id === record.channelId && raw.group_id === record.groupId; }; -export const isRecordTeamEqualToRaw = (record: Team, raw: RawTeam) => { +export const isRecordTeamEqualToRaw = (record: TeamModel, raw: Team) => { return raw.id === record.id; }; -export const isRecordTeamChannelHistoryEqualToRaw = (record: TeamChannelHistory, raw: RawTeamChannelHistory) => { +export const isRecordTeamChannelHistoryEqualToRaw = (record: TeamChannelHistoryModel, raw: TeamChannelHistory) => { return raw.team_id === record.teamId; }; -export const isRecordTeamSearchHistoryEqualToRaw = (record: TeamSearchHistory, raw: RawTeamSearchHistory) => { +export const isRecordTeamSearchHistoryEqualToRaw = (record: TeamSearchHistoryModel, raw: TeamSearchHistory) => { return raw.team_id === record.teamId && raw.term === record.term; }; -export const isRecordSlashCommandEqualToRaw = (record: SlashCommand, raw: RawSlashCommand) => { +export const isRecordSlashCommandEqualToRaw = (record: SlashCommandModel, raw: SlashCommand) => { return raw.id === record.id; }; -export const isRecordMyTeamEqualToRaw = (record: MyTeam, raw: RawMyTeam) => { +export const isRecordMyTeamEqualToRaw = (record: MyTeamModel, raw: MyTeam) => { return raw.team_id === record.teamId; }; -export const isRecordChannelEqualToRaw = (record: Channel, raw: RawChannel) => { +export const isRecordChannelEqualToRaw = (record: ChannelModel, raw: Channel) => { return raw.id === record.id; }; -export const isRecordMyChannelSettingsEqualToRaw = (record: MyChannelSettings, raw: RawMyChannelSettings) => { +export const isRecordMyChannelSettingsEqualToRaw = (record: MyChannelSettingsModel, raw: ChannelMembership) => { return raw.channel_id === record.channelId; }; -export const isRecordChannelInfoEqualToRaw = (record: ChannelInfo, raw: RawChannelInfo) => { +export const isRecordChannelInfoEqualToRaw = (record: ChannelInfoModel, raw: ChannelInfo) => { return raw.channel_id === record.channelId; }; -export const isRecordMyChannelEqualToRaw = (record: MyChannel, raw: RawMyChannel) => { +export const isRecordMyChannelEqualToRaw = (record: MyChannelModel, raw: ChannelMembership) => { return raw.channel_id === record.channelId; }; diff --git a/app/database/operator/server_data_operator/handlers/channel.test.ts b/app/database/operator/server_data_operator/handlers/channel.test.ts index ea743d5265..23872a4322 100644 --- a/app/database/operator/server_data_operator/handlers/channel.test.ts +++ b/app/database/operator/server_data_operator/handlers/channel.test.ts @@ -17,8 +17,6 @@ import { import ServerDataOperator from '..'; -import type {RawChannel} from '@typings/database/database'; - describe('*** Operator: Channel Handlers tests ***', () => { let operator: ServerDataOperator; beforeAll(async () => { @@ -30,7 +28,7 @@ describe('*** Operator: Channel Handlers tests ***', () => { expect.assertions(2); const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords'); - const channels: RawChannel[] = [ + const channels: Channel[] = [ { create_at: 1600185541285, creator_id: '', @@ -42,14 +40,11 @@ describe('*** Operator: Channel Handlers tests ***', () => { id: 'kjlw9j1ttnxwig7tnqgebg7dtipno', last_post_at: 1617311494451, name: 'gh781zkzkhh357b4bejephjz5u8daw__9ciscaqbrpd6d8s68k76xb9bte', - policy_id: 'policy', - props: null, purpose: '', scheme_id: null, shared: false, team_id: '', total_msg_count: 585, - total_msg_count_root: 1, type: 'D', update_at: 1604401077256, }, @@ -75,17 +70,21 @@ describe('*** Operator: Channel Handlers tests ***', () => { expect.assertions(2); const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords'); - const settings = [ + const settings: ChannelMembership[] = [ { + user_id: 'me', channel_id: 'c', + roles: '', + msg_count: 0, + mention_count: 0, + last_viewed_at: 0, + last_update_at: 0, notify_props: { - desktop: 'all', - desktop_sound: true, - email: true, - first_name: true, - mention_keys: '', + desktop: 'default', + email: 'default', + mark_unread: 'mention', push: 'mention', - channel: true, + ignore_channel_mentions: 'default', }, }, ]; @@ -109,7 +108,7 @@ describe('*** Operator: Channel Handlers tests ***', () => { it('=> HandleChannelInfo: should write to the CHANNEL_INFO table', async () => { expect.assertions(2); - const spyOnHandleRecords = jest.spyOn(operator as any, 'handleRecords'); + const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords'); const channelInfos = [ { channel_id: 'c', @@ -142,14 +141,23 @@ describe('*** Operator: Channel Handlers tests ***', () => { expect.assertions(2); const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords'); - const myChannels = [ + const myChannels: ChannelMembership[] = [ { + user_id: 'me', channel_id: 'c', last_post_at: 1617311494451, last_viewed_at: 1617311494451, - mentions_count: 3, - message_count: 10, + last_update_at: 1617311494451, + mention_count: 3, + msg_count: 10, roles: 'guest', + notify_props: { + desktop: 'default', + email: 'default', + mark_unread: 'mention', + push: 'mention', + ignore_channel_mentions: 'default', + }, }, ]; diff --git a/app/database/operator/server_data_operator/handlers/channel.ts b/app/database/operator/server_data_operator/handlers/channel.ts index 6d8e77d71e..99665055c4 100644 --- a/app/database/operator/server_data_operator/handlers/channel.ts +++ b/app/database/operator/server_data_operator/handlers/channel.ts @@ -16,16 +16,12 @@ import { transformMyChannelSettingsRecord, } from '@database/operator/server_data_operator/transformers/channel'; import {getUniqueRawsBy} from '@database/operator/utils/general'; -import Channel from '@typings/database/models/servers/channel'; -import ChannelInfo from '@typings/database/models/servers/channel_info'; -import { - HandleChannelArgs, - HandleChannelInfoArgs, - HandleMyChannelArgs, - HandleMyChannelSettingsArgs, -} from '@typings/database/database'; -import MyChannel from '@typings/database/models/servers/my_channel'; -import MyChannelSettings from '@typings/database/models/servers/my_channel_settings'; + +import type ChannelModel from '@typings/database/models/servers/channel'; +import type ChannelInfoModel from '@typings/database/models/servers/channel_info'; +import type {HandleChannelArgs, HandleChannelInfoArgs, HandleMyChannelArgs, HandleMyChannelSettingsArgs} from '@typings/database/database'; +import type MyChannelModel from '@typings/database/models/servers/my_channel'; +import type MyChannelSettingsModel from '@typings/database/models/servers/my_channel_settings'; const { CHANNEL, @@ -35,10 +31,10 @@ const { } = MM_TABLES.SERVER; export interface ChannelHandlerMix { - handleChannel: ({channels, prepareRecordsOnly}: HandleChannelArgs) => Channel[] | boolean; - handleMyChannelSettings: ({settings, prepareRecordsOnly}: HandleMyChannelSettingsArgs) => MyChannelSettings[] | boolean; - handleChannelInfo: ({channelInfos, prepareRecordsOnly}: HandleChannelInfoArgs) => ChannelInfo[] | boolean; - handleMyChannel: ({myChannels, prepareRecordsOnly}: HandleMyChannelArgs) => MyChannel[] | boolean; + handleChannel: ({channels, prepareRecordsOnly}: HandleChannelArgs) => Promise; + handleMyChannelSettings: ({settings, prepareRecordsOnly}: HandleMyChannelSettingsArgs) => Promise; + handleChannelInfo: ({channelInfos, prepareRecordsOnly}: HandleChannelInfoArgs) => Promise; + handleMyChannel: ({myChannels, prepareRecordsOnly}: HandleMyChannelArgs) => Promise; } const ChannelHandler = (superclass: any) => class extends superclass { @@ -48,11 +44,9 @@ const ChannelHandler = (superclass: any) => class extends superclass { * @param {RawChannel[]} channelsArgs.channels * @param {boolean} channelsArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {Channel[]} + * @returns {Promise} */ - handleChannel = async ({channels, prepareRecordsOnly = true}: HandleChannelArgs) => { - let records: Channel[] = []; - + handleChannel = ({channels, prepareRecordsOnly = true}: HandleChannelArgs): Promise => { if (!channels.length) { throw new DataOperatorException( 'An empty "channels" array has been passed to the handleChannel method', @@ -61,7 +55,7 @@ const ChannelHandler = (superclass: any) => class extends superclass { const createOrUpdateRawValues = getUniqueRawsBy({raws: channels, key: 'id'}); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'id', findMatchingRecordBy: isRecordChannelEqualToRaw, transformer: transformChannelRecord, @@ -69,8 +63,6 @@ const ChannelHandler = (superclass: any) => class extends superclass { createOrUpdateRawValues, tableName: CHANNEL, }); - - return records; }; /** @@ -79,11 +71,9 @@ const ChannelHandler = (superclass: any) => class extends superclass { * @param {RawMyChannelSettings[]} settingsArgs.settings * @param {boolean} settingsArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {MyChannelSettings[]} + * @returns {Promise} */ - handleMyChannelSettings = async ({settings, prepareRecordsOnly = true}: HandleMyChannelSettingsArgs) => { - let records: MyChannelSettings[] = []; - + handleMyChannelSettings = ({settings, prepareRecordsOnly = true}: HandleMyChannelSettingsArgs): Promise => { if (!settings.length) { throw new DataOperatorException( 'An empty "settings" array has been passed to the handleMyChannelSettings method', @@ -92,7 +82,7 @@ const ChannelHandler = (superclass: any) => class extends superclass { const createOrUpdateRawValues = getUniqueRawsBy({raws: settings, key: 'channel_id'}); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'channel_id', findMatchingRecordBy: isRecordMyChannelSettingsEqualToRaw, transformer: transformMyChannelSettingsRecord, @@ -100,8 +90,6 @@ const ChannelHandler = (superclass: any) => class extends superclass { createOrUpdateRawValues, tableName: MY_CHANNEL_SETTINGS, }); - - return records; }; /** @@ -110,11 +98,9 @@ const ChannelHandler = (superclass: any) => class extends superclass { * @param {RawChannelInfo[]} channelInfosArgs.channelInfos * @param {boolean} channelInfosArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {ChannelInfo[]} + * @returns {Promise} */ - handleChannelInfo = async ({channelInfos, prepareRecordsOnly = true}: HandleChannelInfoArgs) => { - let records: ChannelInfo[] = []; - + handleChannelInfo = ({channelInfos, prepareRecordsOnly = true}: HandleChannelInfoArgs): Promise => { if (!channelInfos.length) { throw new DataOperatorException( 'An empty "channelInfos" array has been passed to the handleMyChannelSettings method', @@ -126,7 +112,7 @@ const ChannelHandler = (superclass: any) => class extends superclass { key: 'channel_id', }); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'channel_id', findMatchingRecordBy: isRecordChannelInfoEqualToRaw, transformer: transformChannelInfoRecord, @@ -134,8 +120,6 @@ const ChannelHandler = (superclass: any) => class extends superclass { createOrUpdateRawValues, tableName: CHANNEL_INFO, }); - - return records; }; /** @@ -144,11 +128,9 @@ const ChannelHandler = (superclass: any) => class extends superclass { * @param {RawMyChannel[]} myChannelsArgs.myChannels * @param {boolean} myChannelsArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {MyChannel[]} + * @returns {Promise} */ - handleMyChannel = async ({myChannels, prepareRecordsOnly = true}: HandleMyChannelArgs) => { - let records: MyChannel[] = []; - + handleMyChannel = ({myChannels, prepareRecordsOnly = true}: HandleMyChannelArgs): Promise => { if (!myChannels.length) { throw new DataOperatorException( 'An empty "myChannels" array has been passed to the handleMyChannel method', @@ -160,7 +142,7 @@ const ChannelHandler = (superclass: any) => class extends superclass { key: 'channel_id', }); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'channel_id', findMatchingRecordBy: isRecordMyChannelEqualToRaw, transformer: transformMyChannelRecord, @@ -168,8 +150,6 @@ const ChannelHandler = (superclass: any) => class extends superclass { createOrUpdateRawValues, tableName: MY_CHANNEL, }); - - return records; }; }; diff --git a/app/database/operator/server_data_operator/handlers/group.test.ts b/app/database/operator/server_data_operator/handlers/group.test.ts index b2de70a88e..2fb6ae772e 100644 --- a/app/database/operator/server_data_operator/handlers/group.test.ts +++ b/app/database/operator/server_data_operator/handlers/group.test.ts @@ -28,18 +28,20 @@ describe('*** Operator: Group Handlers tests ***', () => { expect.assertions(2); const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords'); - const groups = [ + const groups: Group[] = [ { id: 'id_groupdfjdlfkjdkfdsf', name: 'mobile_team', display_name: 'mobile team', description: '', - source: '', remote_id: '', create_at: 0, update_at: 0, delete_at: 0, has_syncables: true, + type: '', + member_count: 1, + allow_reference: false, }, ]; diff --git a/app/database/operator/server_data_operator/handlers/group.ts b/app/database/operator/server_data_operator/handlers/group.ts index 5849f1f177..99d96e036f 100644 --- a/app/database/operator/server_data_operator/handlers/group.ts +++ b/app/database/operator/server_data_operator/handlers/group.ts @@ -16,16 +16,12 @@ import { transformGroupsInTeamRecord, } from '@database/operator/server_data_operator/transformers/group'; import {getUniqueRawsBy} from '@database/operator/utils/general'; -import { - HandleGroupArgs, - HandleGroupMembershipArgs, - HandleGroupsInChannelArgs, - HandleGroupsInTeamArgs, -} from '@typings/database/database'; -import Group from '@typings/database/models/servers/group'; -import GroupMembership from '@typings/database/models/servers/group_membership'; -import GroupsInChannel from '@typings/database/models/servers/groups_in_channel'; -import GroupsInTeam from '@typings/database/models/servers/groups_in_team'; + +import type {HandleGroupArgs, HandleGroupMembershipArgs, HandleGroupsInChannelArgs, HandleGroupsInTeamArgs} from '@typings/database/database'; +import type GroupModel from '@typings/database/models/servers/group'; +import type GroupMembershipModel from '@typings/database/models/servers/group_membership'; +import type GroupsInChannelModel from '@typings/database/models/servers/groups_in_channel'; +import type GroupsInTeamModel from '@typings/database/models/servers/groups_in_team'; const { GROUP, @@ -35,10 +31,10 @@ const { } = MM_TABLES.SERVER; export interface GroupHandlerMix { - handleGroupMembership: ({groupMemberships, prepareRecordsOnly}: HandleGroupMembershipArgs) => GroupMembership[] | boolean; - handleGroup: ({groups, prepareRecordsOnly}: HandleGroupArgs) => Group[] | boolean; - handleGroupsInTeam: ({groupsInTeams, prepareRecordsOnly}: HandleGroupsInTeamArgs) => GroupsInTeam[] | boolean; - handleGroupsInChannel: ({groupsInChannels, prepareRecordsOnly}: HandleGroupsInChannelArgs) => GroupsInChannel[] | boolean; + handleGroupMembership: ({groupMemberships, prepareRecordsOnly}: HandleGroupMembershipArgs) => Promise; + handleGroup: ({groups, prepareRecordsOnly}: HandleGroupArgs) => Promise; + handleGroupsInTeam: ({groupsInTeams, prepareRecordsOnly}: HandleGroupsInTeamArgs) => Promise; + handleGroupsInChannel: ({groupsInChannels, prepareRecordsOnly}: HandleGroupsInChannelArgs) => Promise; } const GroupHandler = (superclass: any) => class extends superclass { @@ -48,11 +44,9 @@ const GroupHandler = (superclass: any) => class extends superclass { * @param {RawGroupMembership[]} groupMembershipsArgs.groupMemberships * @param {boolean} groupMembershipsArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {GroupMembership[]} + * @returns {Promise} */ - handleGroupMembership = async ({groupMemberships, prepareRecordsOnly = true}: HandleGroupMembershipArgs) => { - let records: GroupMembership[] = []; - + handleGroupMembership = ({groupMemberships, prepareRecordsOnly = true}: HandleGroupMembershipArgs): Promise => { if (!groupMemberships.length) { throw new DataOperatorException( 'An empty "groupMemberships" array has been passed to the handleGroupMembership method', @@ -61,7 +55,7 @@ const GroupHandler = (superclass: any) => class extends superclass { const createOrUpdateRawValues = getUniqueRawsBy({raws: groupMemberships, key: 'group_id'}); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'user_id', findMatchingRecordBy: isRecordGroupMembershipEqualToRaw, transformer: transformGroupMembershipRecord, @@ -69,8 +63,6 @@ const GroupHandler = (superclass: any) => class extends superclass { createOrUpdateRawValues, tableName: GROUP_MEMBERSHIP, }); - - return records; }; /** @@ -79,11 +71,9 @@ const GroupHandler = (superclass: any) => class extends superclass { * @param {RawGroup[]} groupsArgs.groups * @param {boolean} groupsArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {Group[]} + * @returns {Promise} */ - handleGroup = async ({groups, prepareRecordsOnly = true}: HandleGroupArgs) => { - let records: Group[] = []; - + handleGroup = ({groups, prepareRecordsOnly = true}: HandleGroupArgs): Promise => { if (!groups.length) { throw new DataOperatorException( 'An empty "groups" array has been passed to the handleGroup method', @@ -92,7 +82,7 @@ const GroupHandler = (superclass: any) => class extends superclass { const createOrUpdateRawValues = getUniqueRawsBy({raws: groups, key: 'name'}); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'name', findMatchingRecordBy: isRecordGroupEqualToRaw, transformer: transformGroupRecord, @@ -100,8 +90,6 @@ const GroupHandler = (superclass: any) => class extends superclass { createOrUpdateRawValues, tableName: GROUP, }); - - return records; }; /** @@ -110,11 +98,9 @@ const GroupHandler = (superclass: any) => class extends superclass { * @param {RawGroupsInTeam[]} groupsInTeamsArgs.groupsInTeams * @param {boolean} groupsInTeamsArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {GroupsInTeam[]} + * @returns {Promise} */ - handleGroupsInTeam = async ({groupsInTeams, prepareRecordsOnly = true}: HandleGroupsInTeamArgs) => { - let records: GroupsInTeam[] = []; - + handleGroupsInTeam = ({groupsInTeams, prepareRecordsOnly = true}: HandleGroupsInTeamArgs): Promise => { if (!groupsInTeams.length) { throw new DataOperatorException( 'An empty "groups" array has been passed to the handleGroupsInTeam method', @@ -123,7 +109,7 @@ const GroupHandler = (superclass: any) => class extends superclass { const createOrUpdateRawValues = getUniqueRawsBy({raws: groupsInTeams, key: 'group_id'}); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'group_id', findMatchingRecordBy: isRecordGroupsInTeamEqualToRaw, transformer: transformGroupsInTeamRecord, @@ -131,8 +117,6 @@ const GroupHandler = (superclass: any) => class extends superclass { createOrUpdateRawValues, tableName: GROUPS_IN_TEAM, }); - - return records; }; /** @@ -141,11 +125,9 @@ const GroupHandler = (superclass: any) => class extends superclass { * @param {RawGroupsInChannel[]} groupsInChannelsArgs.groupsInChannels * @param {boolean} groupsInChannelsArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {GroupsInChannel[]} + * @returns {Promise} */ - handleGroupsInChannel = async ({groupsInChannels, prepareRecordsOnly = true}: HandleGroupsInChannelArgs) => { - let records: GroupsInChannel[] = []; - + handleGroupsInChannel = ({groupsInChannels, prepareRecordsOnly = true}: HandleGroupsInChannelArgs): Promise => { if (!groupsInChannels.length) { throw new DataOperatorException( 'An empty "groups" array has been passed to the handleGroupsInTeam method', @@ -154,7 +136,7 @@ const GroupHandler = (superclass: any) => class extends superclass { const createOrUpdateRawValues = getUniqueRawsBy({raws: groupsInChannels, key: 'channel_id'}); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'group_id', findMatchingRecordBy: isRecordGroupsInChannelEqualToRaw, transformer: transformGroupsInChannelRecord, @@ -162,8 +144,6 @@ const GroupHandler = (superclass: any) => class extends superclass { createOrUpdateRawValues, tableName: GROUPS_IN_CHANNEL, }); - - return records; }; }; diff --git a/app/database/operator/server_data_operator/handlers/index.test.ts b/app/database/operator/server_data_operator/handlers/index.test.ts index f24b4f6abb..8a99eab19b 100644 --- a/app/database/operator/server_data_operator/handlers/index.test.ts +++ b/app/database/operator/server_data_operator/handlers/index.test.ts @@ -15,9 +15,10 @@ import { transformSystemRecord, transformTermsOfServiceRecord, } from '@database/operator/server_data_operator/transformers/general'; -import {RawRole, RawTermsOfService} from '@typings/database/database'; -import ServerDataOperator from '..'; +import type {Model} from '@nozbe/watermelondb'; + +import type ServerDataOperator from '..'; describe('*** DataOperator: Base Handlers tests ***', () => { let operator: ServerDataOperator; @@ -31,7 +32,7 @@ describe('*** DataOperator: Base Handlers tests ***', () => { const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords'); - const roles: RawRole[] = [ + const roles: Role[] = [ { id: 'custom-role-id-1', name: 'custom-role-1', @@ -58,7 +59,7 @@ describe('*** DataOperator: Base Handlers tests ***', () => { expect.assertions(2); const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords'); - const emojis = [ + const emojis: CustomEmoji[] = [ { id: 'i', create_at: 1580913641769, @@ -112,7 +113,7 @@ describe('*** DataOperator: Base Handlers tests ***', () => { const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords'); - const termOfService: RawTermsOfService[] = [ + const termOfService: TermsOfService[] = [ { id: 'tos-1', accepted_at: 1, @@ -145,13 +146,20 @@ describe('*** DataOperator: Base Handlers tests ***', () => { expect(appDatabase).toBeTruthy(); expect(appOperator).toBeTruthy(); + const findMatchingRecordBy = (existing: Model, newRecord: any) => { + return existing === newRecord; + }; + + const transformer = async (model: Model) => model; + await expect( operator?.handleRecords({ fieldName: 'invalidField', tableName: 'INVALID_TABLE_NAME', - - // @ts-expect-error: Type does not match RawValue - createOrUpdateRawValues: [{id: 'tos-1', accepted_at: 1}], + findMatchingRecordBy, + transformer, + createOrUpdateRawValues: [{id: 'tos-1', value: '1'}], + prepareRecordsOnly: false, }), ).rejects.toThrow(DataOperatorException); }); diff --git a/app/database/operator/server_data_operator/handlers/index.ts b/app/database/operator/server_data_operator/handlers/index.ts index 792eea32ab..3ac8356147 100644 --- a/app/database/operator/server_data_operator/handlers/index.ts +++ b/app/database/operator/server_data_operator/handlers/index.ts @@ -17,85 +17,82 @@ import { transformTermsOfServiceRecord, } from '@database/operator/server_data_operator/transformers/general'; import {getUniqueRawsBy} from '@database/operator/utils/general'; -import {HandleCustomEmojiArgs, HandleRoleArgs, HandleSystemArgs, HandleTOSArgs, OperationArgs} from '@typings/database/database'; + +import type {HandleCustomEmojiArgs, HandleRoleArgs, HandleSystemArgs, HandleTOSArgs, OperationArgs} from '@typings/database/database'; +import type RoleModel from '@typings/database/models/servers/role'; +import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji'; +import type SystemModel from '@typings/database/models/servers/system'; +import type TermsOfServiceModel from '@typings/database/models/servers/terms_of_service'; const {SERVER: {CUSTOM_EMOJI, ROLE, SYSTEM, TERMS_OF_SERVICE}} = MM_TABLES; export default class ServerDataOperatorBase extends BaseDataOperator { - handleRole = async ({roles, prepareRecordsOnly = true}: HandleRoleArgs) => { + handleRole = ({roles, prepareRecordsOnly = true}: HandleRoleArgs) => { if (!roles.length) { throw new DataOperatorException( 'An empty "values" array has been passed to the handleRole', ); } - const records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'id', findMatchingRecordBy: isRecordRoleEqualToRaw, transformer: transformRoleRecord, prepareRecordsOnly, createOrUpdateRawValues: getUniqueRawsBy({raws: roles, key: 'id'}), tableName: ROLE, - }); - - return records; + }) as Promise; } - handleCustomEmojis = async ({emojis, prepareRecordsOnly = true}: HandleCustomEmojiArgs) => { + handleCustomEmojis = ({emojis, prepareRecordsOnly = true}: HandleCustomEmojiArgs) => { if (!emojis.length) { throw new DataOperatorException( 'An empty "values" array has been passed to the handleCustomEmojis', ); } - const records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'id', findMatchingRecordBy: isRecordCustomEmojiEqualToRaw, transformer: transformCustomEmojiRecord, prepareRecordsOnly, createOrUpdateRawValues: getUniqueRawsBy({raws: emojis, key: 'id'}), tableName: CUSTOM_EMOJI, - }); - - return records; + }) as Promise; } - handleSystem = async ({systems, prepareRecordsOnly = true}: HandleSystemArgs) => { + handleSystem = ({systems, prepareRecordsOnly = true}: HandleSystemArgs) => { if (!systems.length) { throw new DataOperatorException( 'An empty "values" array has been passed to the handleSystem', ); } - const records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'id', findMatchingRecordBy: isRecordSystemEqualToRaw, transformer: transformSystemRecord, prepareRecordsOnly, createOrUpdateRawValues: getUniqueRawsBy({raws: systems, key: 'id'}), tableName: SYSTEM, - }); - - return records; + }) as Promise; } - handleTermOfService = async ({termOfService, prepareRecordsOnly = true}: HandleTOSArgs) => { + handleTermOfService = ({termOfService, prepareRecordsOnly = true}: HandleTOSArgs) => { if (!termOfService.length) { throw new DataOperatorException( 'An empty "values" array has been passed to the handleTermOfService', ); } - const records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'id', findMatchingRecordBy: isRecordTermsOfServiceEqualToRaw, transformer: transformTermsOfServiceRecord, prepareRecordsOnly, createOrUpdateRawValues: getUniqueRawsBy({raws: termOfService, key: 'id'}), tableName: TERMS_OF_SERVICE, - }); - - return records; + }) as Promise; } /** @@ -107,7 +104,7 @@ export default class ServerDataOperatorBase extends BaseDataOperator { * @param {(TransformerArgs) => Promise} execute.recordOperator * @returns {Promise} */ - execute = async ({createRaws, transformer, tableName, updateRaws}: OperationArgs) => { + execute = async ({createRaws, transformer, tableName, updateRaws}: OperationArgs): Promise => { const models = await this.prepareRecords({ tableName, createRaws, diff --git a/app/database/operator/server_data_operator/handlers/post.test.ts b/app/database/operator/server_data_operator/handlers/post.test.ts index 42218eaf03..d4ee24bd06 100644 --- a/app/database/operator/server_data_operator/handlers/post.test.ts +++ b/app/database/operator/server_data_operator/handlers/post.test.ts @@ -58,9 +58,9 @@ describe('*** Operator: Post Handlers tests ***', () => { }); it('=> HandlePosts: should write to the Post and its sub-child tables', async () => { - expect.assertions(12); + // expect.assertions(12); - const posts = [ + const posts: Post[] = [ { id: '8swgtrrdiff89jnsiwiip3y1eoe', create_at: 1596032651747, @@ -96,8 +96,6 @@ describe('*** Operator: Post Handlers tests ***', () => { post_id: 'a7ebyw883trm884p1qcgt8yw4a', emoji_name: 'clap', create_at: 1608252965442, - update_at: 1608252965442, - delete_at: 0, }, ], embeds: [ @@ -235,8 +233,6 @@ describe('*** Operator: Post Handlers tests ***', () => { post_id: 'a7ebyw883trm884p1qcgt8yw4a', emoji_name: 'clap', create_at: 1608252965442, - update_at: 1608252965442, - delete_at: 0, }, ], prepareRecordsOnly: true, @@ -268,9 +264,9 @@ describe('*** Operator: Post Handlers tests ***', () => { expect(spyOnHandlePostMetadata).toHaveBeenCalledTimes(1); expect(spyOnHandlePostMetadata).toHaveBeenCalledWith({ - embeds: [ - { - embed: [ + metadatas: [{ + data: { + embeds: [ { type: 'opengraph', url: 'https://github.com/mickmister/mattermost-plugin-default-theme', @@ -297,11 +293,6 @@ describe('*** Operator: Post Handlers tests ***', () => { }, }, ], - postId: '8swgtrrdiff89jnsiwiip3y1eoe', - }, - ], - images: [ - { images: { 'https://community-release.mattermost.com/api/v4/image?url=https%3A%2F%2Favatars1.githubusercontent.com%2Fu%2F6913320%3Fs%3D400%26v%3D4': { width: 400, @@ -310,9 +301,9 @@ describe('*** Operator: Post Handlers tests ***', () => { frame_count: 0, }, }, - postId: '8swgtrrdiff89jnsiwiip3y1eoe', }, - ], + post_id: '8swgtrrdiff89jnsiwiip3y1eoe', + }], prepareRecordsOnly: true, }); diff --git a/app/database/operator/server_data_operator/handlers/post.ts b/app/database/operator/server_data_operator/handlers/post.ts index 0d21a850d2..d8efa67152 100644 --- a/app/database/operator/server_data_operator/handlers/post.ts +++ b/app/database/operator/server_data_operator/handlers/post.ts @@ -17,27 +17,15 @@ import { } from '@database/operator/server_data_operator/transformers/post'; import {getRawRecordPairs, getUniqueRawsBy, retrieveRecords} from '@database/operator/utils/general'; import {createPostsChain, sanitizePosts} from '@database/operator/utils/post'; -import { - HandleDraftArgs, - HandleFilesArgs, - HandlePostMetadataArgs, - HandlePostsArgs, - PostImage, - RawCustomEmoji, - RawEmbed, - RawFile, - RawPost, - RawPostMetadata, - RawPostsInThread, - RawReaction, RecordPair, -} from '@typings/database/database'; -import Draft from '@typings/database/models/servers/draft'; -import File from '@typings/database/models/servers/file'; -import Post from '@typings/database/models/servers/post'; -import PostMetadata from '@typings/database/models/servers/post_metadata'; -import PostsInChannel from '@typings/database/models/servers/posts_in_channel'; -import PostsInThread from '@typings/database/models/servers/posts_in_thread'; -import Reaction from '@typings/database/models/servers/reaction'; + +import type {HandleDraftArgs, HandleFilesArgs, HandlePostMetadataArgs, HandlePostsArgs, RecordPair} from '@typings/database/database'; +import type DraftModel from '@typings/database/models/servers/draft'; +import type FileModel from '@typings/database/models/servers/file'; +import type PostModel from '@typings/database/models/servers/post'; +import type PostMetadataModel from '@typings/database/models/servers/post_metadata'; +import type PostsInChannelModel from '@typings/database/models/servers/posts_in_channel'; +import type PostsInThreadModel from '@typings/database/models/servers/posts_in_thread'; +import type ReactionModel from '@typings/database/models/servers/reaction'; const { DRAFT, @@ -49,12 +37,12 @@ const { } = MM_TABLES.SERVER; export interface PostHandlerMix { - handleDraft: ({drafts, prepareRecordsOnly}: HandleDraftArgs) => Draft[] | boolean; - handleFiles: ({files, prepareRecordsOnly}: HandleFilesArgs) => Promise; - handlePostMetadata: ({embeds, images, prepareRecordsOnly}: HandlePostMetadataArgs) => Promise; + handleDraft: ({drafts, prepareRecordsOnly}: HandleDraftArgs) => Promise; + handleFiles: ({files, prepareRecordsOnly}: HandleFilesArgs) => Promise; + handlePostMetadata: ({metadatas, prepareRecordsOnly}: HandlePostMetadataArgs) => Promise; handlePosts: ({orders, values, previousPostId}: HandlePostsArgs) => Promise; - handlePostsInChannel: (posts: RawPost[]) => Promise; - handlePostsInThread: (rootPosts: RawPostsInThread[]) => Promise; + handlePostsInChannel: (posts: Post[]) => Promise; + handlePostsInThread: (rootPosts: PostsInThread[]) => Promise; } const PostHandler = (superclass: any) => class extends superclass { @@ -64,11 +52,9 @@ const PostHandler = (superclass: any) => class extends superclass { * @param {RawDraft[]} draftsArgs.drafts * @param {boolean} draftsArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {Draft[]} + * @returns {Promise} */ - handleDraft = async ({drafts, prepareRecordsOnly = true}: HandleDraftArgs) => { - let records: Draft[] = []; - + handleDraft = ({drafts, prepareRecordsOnly = true}: HandleDraftArgs): Promise => { if (!drafts.length) { throw new DataOperatorException( 'An empty "drafts" array has been passed to the handleDraft method', @@ -77,7 +63,7 @@ const PostHandler = (superclass: any) => class extends superclass { const createOrUpdateRawValues = getUniqueRawsBy({raws: drafts, key: 'channel_id'}); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'channel_id', findMatchingRecordBy: isRecordDraftEqualToRaw, transformer: transformDraftRecord, @@ -85,8 +71,6 @@ const PostHandler = (superclass: any) => class extends superclass { createOrUpdateRawValues, tableName: DRAFT, }); - - return records; }; /** @@ -97,7 +81,7 @@ const PostHandler = (superclass: any) => class extends superclass { * @param {string | undefined} handlePosts.previousPostId * @returns {Promise} */ - handlePosts = async ({orders, values, previousPostId}: HandlePostsArgs) => { + handlePosts = async ({orders, values, previousPostId}: HandlePostsArgs): Promise => { const tableName = POST; // We rely on the order array; if it is empty, we stop processing @@ -110,7 +94,7 @@ const PostHandler = (superclass: any) => class extends superclass { const rawValues = getUniqueRawsBy({ raws: values, key: 'id', - }) as RawPost[]; + }) as Post[]; // By sanitizing the values, we are separating 'posts' that needs updating ( i.e. un-ordered posts ) from those that need to be created in our database const {postsOrdered, postsUnordered} = sanitizePosts({ @@ -128,12 +112,11 @@ const PostHandler = (superclass: any) => class extends superclass { if (futureEntries.createRaws?.length) { let batch: Model[] = []; - let files: RawFile[] = []; + const files: FileInfo[] = []; const postsInThread = []; - let reactions: RawReaction[] = []; - let emojis: RawCustomEmoji[] = []; - const images: Array<{ images: Dictionary; postId: string }> = []; - const embeds: Array<{ embed: RawEmbed[]; postId: string }> = []; + const reactions: Reaction[] = []; + const emojis: CustomEmoji[] = []; + const metadatas: Metadata[] = []; // We create the 'chain of posts' by linking each posts' previousId to the post before it in the order array const linkedRawPosts: RecordPair[] = createPostsChain({ @@ -147,7 +130,7 @@ const PostHandler = (superclass: any) => class extends superclass { createRaws: linkedRawPosts, transformer: transformPostRecord, tableName, - })) as Post[]; + })) as PostModel[]; // Appends the processed records into the final batch array batch = batch.concat(posts); @@ -163,31 +146,36 @@ const PostHandler = (superclass: any) => class extends superclass { } if (post?.metadata && Object.keys(post?.metadata).length > 0) { - const metadata = post.metadata; + const data = post.metadata; // Extracts reaction from post's metadata - reactions = reactions.concat(metadata?.reactions ?? []); + if (data.reactions) { + reactions.push(...data.reactions); + delete data.reactions; + } // Extracts emojis from post's metadata - emojis = emojis.concat(metadata?.emojis ?? []); + if (data.emojis) { + emojis.push(...data.emojis); + delete data.emojis; + } // Extracts files from post's metadata - files = files.concat(metadata?.files ?? []); - - // Extracts images and embeds from post's metadata - if (metadata?.images) { - images.push({images: metadata.images, postId: post.id}); + if (data.files) { + files.push(...data.files); + delete data.files; } - if (metadata?.embeds) { - embeds.push({embed: metadata.embeds, postId: post.id}); - } + metadatas.push({ + data, + post_id: post.id, + }); } } if (reactions.length) { // calls handler for Reactions - const postReactions = (await this.handleReactions({reactions, prepareRecordsOnly: true})) as Reaction[]; + const postReactions = (await this.handleReactions({reactions, prepareRecordsOnly: true})) as ReactionModel[]; batch = batch.concat(postReactions); } @@ -197,11 +185,10 @@ const PostHandler = (superclass: any) => class extends superclass { batch = batch.concat(postFiles); } - if (images.length || embeds.length) { + if (metadatas.length) { // calls handler for postMetadata ( embeds and images ) const postMetadata = await this.handlePostMetadata({ - images, - embeds, + metadatas, prepareRecordsOnly: true, }); @@ -230,7 +217,7 @@ const PostHandler = (superclass: any) => class extends superclass { } if (postsUnordered.length) { - // Truly update those posts that have a different update_at value + // Truly update those posts that have a different update_at value await this.handleRecords({ findMatchingRecordBy: isRecordPostEqualToRaw, fieldName: 'id', @@ -247,9 +234,9 @@ const PostHandler = (superclass: any) => class extends superclass { * @param {HandleFilesArgs} handleFiles * @param {RawFile[]} handleFiles.files * @param {boolean} handleFiles.prepareRecordsOnly - * @returns {Promise} + * @returns {Promise} */ - handleFiles = async ({files, prepareRecordsOnly}: HandleFilesArgs) => { + handleFiles = async ({files, prepareRecordsOnly}: HandleFilesArgs): Promise => { if (!files.length) { return []; } @@ -268,7 +255,7 @@ const PostHandler = (superclass: any) => class extends superclass { await this.batchRecords(postFiles); } - return []; + return postFiles; }; /** @@ -277,40 +264,11 @@ const PostHandler = (superclass: any) => class extends superclass { * @param {{embed: RawEmbed[], postId: string}[] | undefined} handlePostMetadata.embeds * @param {{images: Dictionary, postId: string}[] | undefined} handlePostMetadata.images * @param {boolean} handlePostMetadata.prepareRecordsOnly - * @returns {Promise} + * @returns {Promise} */ - handlePostMetadata = async ({embeds, images, prepareRecordsOnly}: HandlePostMetadataArgs) => { - const metadata: RawPostMetadata[] = []; - - if (images?.length) { - images.forEach((image) => { - const imageEntry = Object.entries(image.images); - metadata.push({ - data: {...imageEntry?.[0]?.[1], url: imageEntry?.[0]?.[0]}, - type: 'images', - postId: image.postId, - }); - }); - } - - if (embeds?.length) { - embeds.forEach((postEmbed) => { - postEmbed.embed.forEach((embed: RawEmbed) => { - metadata.push({ - data: {...embed.data}, - type: embed.type, - postId: postEmbed.postId, - }); - }); - }); - } - - if (!metadata.length) { - return []; - } - + handlePostMetadata = async ({metadatas, prepareRecordsOnly}: HandlePostMetadataArgs): Promise => { const postMetas = await this.prepareRecords({ - createRaws: getRawRecordPairs(metadata), + createRaws: getRawRecordPairs([metadatas]), transformer: transformPostMetadataRecord, tableName: POST_METADATA, }); @@ -323,31 +281,31 @@ const PostHandler = (superclass: any) => class extends superclass { await this.batchRecords(postMetas); } - return []; + return postMetas; }; /** * handlePostsInThread: Handler responsible for the Create/Update operations occurring on the PostsInThread table from the 'Server' schema - * @param {RawPostsInThread[]} rootPosts + * @param {PostsInThread[]} rootPosts * @returns {Promise} */ - handlePostsInThread = async (rootPosts: RawPostsInThread[]) => { + handlePostsInThread = async (rootPosts: PostsInThread[]): Promise => { if (!rootPosts.length) { return; } const postIds = rootPosts.map((postThread) => postThread.post_id); - const rawPostsInThreads: RawPostsInThread[] = []; + const rawPostsInThreads: PostsInThread[] = []; // Retrieves all threads whereby their root_id can be one of the element in the postIds array const threads = (await this.database.collections. get(POST). query(Q.where('root_id', Q.oneOf(postIds))). - fetch()) as Post[]; + fetch()) as PostModel[]; // The aim here is to find the last reply in that thread; hence the latest create_at value rootPosts.forEach((rootPost) => { - const maxCreateAt: number = threads.reduce((max: number, thread: Post) => { + const maxCreateAt: number = threads.reduce((max: number, thread: PostModel) => { return thread.createAt > max ? thread.createAt : maxCreateAt; }, 0); @@ -360,7 +318,7 @@ const PostHandler = (superclass: any) => class extends superclass { createRaws: getRawRecordPairs(rawPostsInThreads), transformer: transformPostInThreadRecord, tableName: POSTS_IN_THREAD, - })) as PostsInThread[]; + })) as PostsInThreadModel[]; if (postInThreadRecords?.length) { await this.batchRecords(postInThreadRecords); @@ -370,15 +328,15 @@ const PostHandler = (superclass: any) => class extends superclass { /** * handlePostsInChannel: Handler responsible for the Create/Update operations occurring on the PostsInChannel table from the 'Server' schema - * @param {RawPost[]} posts + * @param {Post[]} posts * @returns {Promise} */ - handlePostsInChannel = async (posts: RawPost[]) => { + handlePostsInChannel = async (posts: Post[]): Promise => { // At this point, the parameter 'posts' is already a chain of posts. Now, we have to figure out how to plug it // into existing chains in the PostsInChannel table if (!posts.length) { - return []; + return; } // Sort a clone of 'posts' array by create_at @@ -387,7 +345,7 @@ const PostHandler = (superclass: any) => class extends superclass { }); // The first element (beginning of chain) - const tipOfChain: RawPost = sortedPosts[0]; + const tipOfChain: Post = sortedPosts[0]; // Channel Id for this chain of posts const channelId = tipOfChain.channel_id; @@ -404,7 +362,7 @@ const PostHandler = (superclass: any) => class extends superclass { database: this.database, tableName: POSTS_IN_CHANNEL, condition: Q.where('channel_id', channelId), - })) as PostsInChannel[]; + })) as PostsInChannelModel[]; const createPostsInChannelRecord = async () => { await this.execute({ @@ -417,7 +375,7 @@ const PostHandler = (superclass: any) => class extends superclass { // chunk length 0; then it's a new chunk to be added to the PostsInChannel table if (chunks.length === 0) { await createPostsInChannelRecord(); - return []; + return; } // Sort chunks (in-place) by earliest field ( oldest to newest ) @@ -426,7 +384,7 @@ const PostHandler = (superclass: any) => class extends superclass { }); let found = false; - let targetChunk: PostsInChannel; + let targetChunk: PostsInChannelModel; for (const chunk of chunks) { // find if we should plug the chain before @@ -446,7 +404,7 @@ const PostHandler = (superclass: any) => class extends superclass { database: this.database, tableName: POST, condition: Q.where('create_at', earliest), - })) as Post[]; + })) as PostModel[]; if (potentialPosts?.length > 0) { const targetPost = potentialPosts[0]; @@ -463,15 +421,11 @@ const PostHandler = (superclass: any) => class extends superclass { }); } else { await createPostsInChannelRecord(); - return []; } } } else { await createPostsInChannelRecord(); - return []; } - - return []; }; }; diff --git a/app/database/operator/server_data_operator/handlers/team.test.ts b/app/database/operator/server_data_operator/handlers/team.test.ts index 4f500eedc8..a78994e419 100644 --- a/app/database/operator/server_data_operator/handlers/team.test.ts +++ b/app/database/operator/server_data_operator/handlers/team.test.ts @@ -32,7 +32,7 @@ describe('*** Operator: Team Handlers tests ***', () => { expect.assertions(2); const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords'); - const teams = [ + const teams: Team[] = [ { id: 'rcgiyftm7jyrxnmdfdfa1osd8zswby', create_at: 1445538153952, @@ -73,16 +73,16 @@ describe('*** Operator: Team Handlers tests ***', () => { expect.assertions(2); const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords'); - const teamMemberships = [ + const teamMemberships: TeamMembership[] = [ { team_id: 'a', user_id: 'ab', - roles: '3ngdqe1e7tfcbmam4qgnxp91bw', + roles: '', delete_at: 0, - scheme_guest: false, + msg_count: 0, + mention_count: 0, scheme_user: true, scheme_admin: false, - explicit_roles: '', }, ]; @@ -162,7 +162,7 @@ describe('*** Operator: Team Handlers tests ***', () => { expect.assertions(2); const spyOnHandleRecords = jest.spyOn(operator, 'handleRecords'); - const teamSearchHistories = [ + const teamSearchHistories: TeamSearchHistory[] = [ { team_id: 'a', term: 'termA', diff --git a/app/database/operator/server_data_operator/handlers/team.ts b/app/database/operator/server_data_operator/handlers/team.ts index 650cb3bbd9..02195d63d8 100644 --- a/app/database/operator/server_data_operator/handlers/team.ts +++ b/app/database/operator/server_data_operator/handlers/team.ts @@ -20,20 +20,17 @@ import { transformTeamSearchHistoryRecord, } from '@database/operator/server_data_operator/transformers/team'; import {getUniqueRawsBy} from '@database/operator/utils/general'; -import { - HandleMyTeamArgs, - HandleSlashCommandArgs, - HandleTeamArgs, - HandleTeamChannelHistoryArgs, - HandleTeamMembershipArgs, - HandleTeamSearchHistoryArgs, + +import type { + HandleMyTeamArgs, HandleSlashCommandArgs, HandleTeamArgs, + HandleTeamChannelHistoryArgs, HandleTeamMembershipArgs, HandleTeamSearchHistoryArgs, } from '@typings/database/database'; -import MyTeam from '@typings/database/models/servers/my_team'; -import SlashCommand from '@typings/database/models/servers/slash_command'; -import Team from '@typings/database/models/servers/team'; -import TeamChannelHistory from '@typings/database/models/servers/team_channel_history'; -import TeamMembership from '@typings/database/models/servers/team_membership'; -import TeamSearchHistory from '@typings/database/models/servers/team_search_history'; +import type MyTeamModel from '@typings/database/models/servers/my_team'; +import type SlashCommandModel from '@typings/database/models/servers/slash_command'; +import type TeamModel from '@typings/database/models/servers/team'; +import type TeamChannelHistoryModel from '@typings/database/models/servers/team_channel_history'; +import type TeamMembershipModel from '@typings/database/models/servers/team_membership'; +import type TeamSearchHistoryModel from '@typings/database/models/servers/team_search_history'; const { MY_TEAM, @@ -45,25 +42,24 @@ const { } = MM_TABLES.SERVER; export interface TeamHandlerMix { - handleTeamMemberships: ({teamMemberships, prepareRecordsOnly}: HandleTeamMembershipArgs) => TeamMembership[]; - handleTeam: ({teams, prepareRecordsOnly}: HandleTeamArgs) => Team[]; - handleTeamChannelHistory: ({teamChannelHistories, prepareRecordsOnly}: HandleTeamChannelHistoryArgs) => TeamChannelHistory[]; - handleSlashCommand: ({slashCommands, prepareRecordsOnly}: HandleSlashCommandArgs) => SlashCommand[]; - handleMyTeam: ({myTeams, prepareRecordsOnly}: HandleMyTeamArgs) => MyTeam[]; + handleTeamMemberships: ({teamMemberships, prepareRecordsOnly}: HandleTeamMembershipArgs) => Promise; + handleTeam: ({teams, prepareRecordsOnly}: HandleTeamArgs) => Promise; + handleTeamChannelHistory: ({teamChannelHistories, prepareRecordsOnly}: HandleTeamChannelHistoryArgs) => Promise; + handleTeamSearchHistory: ({teamSearchHistories, prepareRecordsOnly}: HandleTeamSearchHistoryArgs) => Promise; + handleSlashCommand: ({slashCommands, prepareRecordsOnly}: HandleSlashCommandArgs) => Promise; + handleMyTeam: ({myTeams, prepareRecordsOnly}: HandleMyTeamArgs) => Promise; } const TeamHandler = (superclass: any) => class extends superclass { /** * handleTeamMemberships: Handler responsible for the Create/Update operations occurring on the TEAM_MEMBERSHIP table from the 'Server' schema * @param {HandleTeamMembershipArgs} teamMembershipsArgs - * @param {RawTeamMembership[]} teamMembershipsArgs.teamMemberships + * @param {TeamMembership[]} teamMembershipsArgs.teamMemberships * @param {boolean} teamMembershipsArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {TeamMembership[]} + * @returns {Promise} */ - handleTeamMemberships = async ({teamMemberships, prepareRecordsOnly = true}: HandleTeamMembershipArgs) => { - let records: TeamMembership[] = []; - + handleTeamMemberships = ({teamMemberships, prepareRecordsOnly = true}: HandleTeamMembershipArgs): Promise => { if (!teamMemberships.length) { throw new DataOperatorException( 'An empty "teamMemberships" array has been passed to the handleTeamMemberships method', @@ -72,7 +68,7 @@ const TeamHandler = (superclass: any) => class extends superclass { const createOrUpdateRawValues = getUniqueRawsBy({raws: teamMemberships, key: 'team_id'}); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'user_id', findMatchingRecordBy: isRecordTeamMembershipEqualToRaw, transformer: transformTeamMembershipRecord, @@ -80,21 +76,17 @@ const TeamHandler = (superclass: any) => class extends superclass { tableName: TEAM_MEMBERSHIP, prepareRecordsOnly, }); - - return records; }; /** * handleTeam: Handler responsible for the Create/Update operations occurring on the TEAM table from the 'Server' schema * @param {HandleTeamArgs} teamsArgs - * @param {RawTeam[]} teamsArgs.teams + * @param {Team[]} teamsArgs.teams * @param {boolean} teamsArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {Team[]} + * @returns {Promise} */ - handleTeam = async ({teams, prepareRecordsOnly = true}: HandleTeamArgs) => { - let records: Team[] = []; - + handleTeam = ({teams, prepareRecordsOnly = true}: HandleTeamArgs): Promise => { if (!teams.length) { throw new DataOperatorException( 'An empty "teams" array has been passed to the handleTeam method', @@ -103,7 +95,7 @@ const TeamHandler = (superclass: any) => class extends superclass { const createOrUpdateRawValues = getUniqueRawsBy({raws: teams, key: 'id'}); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'id', findMatchingRecordBy: isRecordTeamEqualToRaw, transformer: transformTeamRecord, @@ -111,21 +103,17 @@ const TeamHandler = (superclass: any) => class extends superclass { createOrUpdateRawValues, tableName: TEAM, }); - - return records; }; /** * handleTeamChannelHistory: Handler responsible for the Create/Update operations occurring on the TEAM_CHANNEL_HISTORY table from the 'Server' schema * @param {HandleTeamChannelHistoryArgs} teamChannelHistoriesArgs - * @param {RawTeamChannelHistory[]} teamChannelHistoriesArgs.teamChannelHistories + * @param {TeamChannelHistory[]} teamChannelHistoriesArgs.teamChannelHistories * @param {boolean} teamChannelHistoriesArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {TeamChannelHistory[]} + * @returns {Promise} */ - handleTeamChannelHistory = async ({teamChannelHistories, prepareRecordsOnly = true}: HandleTeamChannelHistoryArgs) => { - let records: TeamChannelHistory[] = []; - + handleTeamChannelHistory = ({teamChannelHistories, prepareRecordsOnly = true}: HandleTeamChannelHistoryArgs): Promise => { if (!teamChannelHistories.length) { throw new DataOperatorException( 'An empty "teamChannelHistories" array has been passed to the handleTeamChannelHistory method', @@ -134,7 +122,7 @@ const TeamHandler = (superclass: any) => class extends superclass { const createOrUpdateRawValues = getUniqueRawsBy({raws: teamChannelHistories, key: 'team_id'}); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'team_id', findMatchingRecordBy: isRecordTeamChannelHistoryEqualToRaw, transformer: transformTeamChannelHistoryRecord, @@ -142,21 +130,17 @@ const TeamHandler = (superclass: any) => class extends superclass { createOrUpdateRawValues, tableName: TEAM_CHANNEL_HISTORY, }); - - return records; }; /** * handleTeamSearchHistory: Handler responsible for the Create/Update operations occurring on the TEAM_SEARCH_HISTORY table from the 'Server' schema * @param {HandleTeamSearchHistoryArgs} teamSearchHistoriesArgs - * @param {RawTeamSearchHistory[]} teamSearchHistoriesArgs.teamSearchHistories + * @param {TeamSearchHistory[]} teamSearchHistoriesArgs.teamSearchHistories * @param {boolean} teamSearchHistoriesArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {TeamSearchHistory[]} + * @returns {Promise} */ - handleTeamSearchHistory = async ({teamSearchHistories, prepareRecordsOnly = true}: HandleTeamSearchHistoryArgs) => { - let records: TeamSearchHistory[] = []; - + handleTeamSearchHistory = ({teamSearchHistories, prepareRecordsOnly = true}: HandleTeamSearchHistoryArgs): Promise => { if (!teamSearchHistories.length) { throw new DataOperatorException( 'An empty "teamSearchHistories" array has been passed to the handleTeamSearchHistory method', @@ -165,7 +149,7 @@ const TeamHandler = (superclass: any) => class extends superclass { const createOrUpdateRawValues = getUniqueRawsBy({raws: teamSearchHistories, key: 'term'}); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'team_id', findMatchingRecordBy: isRecordTeamSearchHistoryEqualToRaw, transformer: transformTeamSearchHistoryRecord, @@ -173,21 +157,17 @@ const TeamHandler = (superclass: any) => class extends superclass { createOrUpdateRawValues, tableName: TEAM_SEARCH_HISTORY, }); - - return records; }; /** * handleSlashCommand: Handler responsible for the Create/Update operations occurring on the SLASH_COMMAND table from the 'Server' schema * @param {HandleSlashCommandArgs} slashCommandsArgs - * @param {RawSlashCommand[]} slashCommandsArgs.slashCommands + * @param {SlashCommand[]} slashCommandsArgs.slashCommands * @param {boolean} slashCommandsArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {SlashCommand[]} + * @returns {Promise} */ - handleSlashCommand = async ({slashCommands, prepareRecordsOnly = true}: HandleSlashCommandArgs) => { - let records: SlashCommand[] = []; - + handleSlashCommand = ({slashCommands, prepareRecordsOnly = true}: HandleSlashCommandArgs): Promise => { if (!slashCommands.length) { throw new DataOperatorException( 'An empty "slashCommands" array has been passed to the handleSlashCommand method', @@ -196,7 +176,7 @@ const TeamHandler = (superclass: any) => class extends superclass { const createOrUpdateRawValues = getUniqueRawsBy({raws: slashCommands, key: 'id'}); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'id', findMatchingRecordBy: isRecordSlashCommandEqualToRaw, transformer: transformSlashCommandRecord, @@ -204,21 +184,17 @@ const TeamHandler = (superclass: any) => class extends superclass { createOrUpdateRawValues, tableName: SLASH_COMMAND, }); - - return records; }; /** * handleMyTeam: Handler responsible for the Create/Update operations occurring on the MY_TEAM table from the 'Server' schema * @param {HandleMyTeamArgs} myTeamsArgs - * @param {RawMyTeam[]} myTeamsArgs.myTeams + * @param {MyTeam[]} myTeamsArgs.myTeams * @param {boolean} myTeamsArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {MyTeam[]} + * @returns {Promise} */ - handleMyTeam = async ({myTeams, prepareRecordsOnly = true}: HandleMyTeamArgs) => { - let records: MyTeam[] = []; - + handleMyTeam = ({myTeams, prepareRecordsOnly = true}: HandleMyTeamArgs): Promise => { if (!myTeams.length) { throw new DataOperatorException( 'An empty "myTeams" array has been passed to the handleSlashCommand method', @@ -227,7 +203,7 @@ const TeamHandler = (superclass: any) => class extends superclass { const createOrUpdateRawValues = getUniqueRawsBy({raws: myTeams, key: 'team_id'}); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'team_id', findMatchingRecordBy: isRecordMyTeamEqualToRaw, transformer: transformMyTeamRecord, @@ -235,8 +211,6 @@ const TeamHandler = (superclass: any) => class extends superclass { createOrUpdateRawValues, tableName: MY_TEAM, }); - - return records; }; }; diff --git a/app/database/operator/server_data_operator/handlers/user.test.ts b/app/database/operator/server_data_operator/handlers/user.test.ts index 8ac3491e4a..a3b2c46d5b 100644 --- a/app/database/operator/server_data_operator/handlers/user.test.ts +++ b/app/database/operator/server_data_operator/handlers/user.test.ts @@ -32,10 +32,8 @@ describe('*** Operator: User Handlers tests ***', () => { reactions: [ { create_at: 1608263728086, - delete_at: 0, emoji_name: 'p4p1', post_id: '4r9jmr7eqt8dxq3f9woypzurry', - update_at: 1608263728077, user_id: 'ooumoqgq3bfiijzwbn8badznwc', }, ], @@ -52,7 +50,7 @@ describe('*** Operator: User Handlers tests ***', () => { it('=> HandleUsers: should write to the User table', async () => { expect.assertions(2); - const users = [ + const users: UserProfile[] = [ { id: '9ciscaqbrpd6d8s68k76xb9bte', create_at: 1599457495881, @@ -71,19 +69,19 @@ describe('*** Operator: User Handlers tests ***', () => { props: {}, notify_props: { desktop: 'all', - desktop_sound: true, - email: true, - first_name: true, + desktop_sound: 'true', + email: 'true', + first_name: 'true', + mark_unread: 'mention', mention_keys: '', push: 'mention', - channel: true, - auto_responder_active: false, + channel: 'true', + auto_responder_active: 'false', auto_responder_message: 'Hello, I am out of office and unable to respond to messages.', comments: 'never', desktop_notification_sound: 'Hello', push_status: 'online', }, - last_password_update: 1604323112537, last_picture_update: 1604686302260, locale: 'en', timezone: { @@ -159,7 +157,7 @@ describe('*** Operator: User Handlers tests ***', () => { it('=> HandleChannelMembership: should write to the CHANNEL_MEMBERSHIP table', async () => { expect.assertions(2); - const channelMemberships = [ + const channelMemberships: ChannelMembership[] = [ { channel_id: '17bfnb1uwb8epewp4q3x3rx9go', user_id: '9ciscaqbrpd6d8s68k76xb9bte', @@ -175,10 +173,8 @@ describe('*** Operator: User Handlers tests ***', () => { push: 'default', }, last_update_at: 1613667352029, - scheme_guest: false, scheme_user: true, scheme_admin: false, - explicit_roles: '', }, { channel_id: '1yw6gxfr4bn1jbyp9nr7d53yew', @@ -195,10 +191,8 @@ describe('*** Operator: User Handlers tests ***', () => { push: 'default', }, last_update_at: 1615300540549, - scheme_guest: false, scheme_user: true, scheme_admin: false, - explicit_roles: '', }, ]; diff --git a/app/database/operator/server_data_operator/handlers/user.ts b/app/database/operator/server_data_operator/handlers/user.ts index 127d9e1ce2..c40a3dd639 100644 --- a/app/database/operator/server_data_operator/handlers/user.ts +++ b/app/database/operator/server_data_operator/handlers/user.ts @@ -17,18 +17,18 @@ import { } from '@database/operator/server_data_operator/transformers/user'; import {getRawRecordPairs, getUniqueRawsBy} from '@database/operator/utils/general'; import {sanitizeReactions} from '@database/operator/utils/reaction'; -import ChannelMembership from '@typings/database/models/servers/channel_membership'; -import CustomEmoji from '@typings/database/models/servers/custom_emoji'; -import { + +import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership'; +import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji'; +import type { HandleChannelMembershipArgs, HandlePreferencesArgs, HandleReactionsArgs, HandleUsersArgs, - RawReaction, } from '@typings/database/database'; -import Preference from '@typings/database/models/servers/preference'; -import Reaction from '@typings/database/models/servers/reaction'; -import User from '@typings/database/models/servers/user'; +import type PreferenceModel from '@typings/database/models/servers/preference'; +import type ReactionModel from '@typings/database/models/servers/reaction'; +import type UserModel from '@typings/database/models/servers/user'; const { CHANNEL_MEMBERSHIP, @@ -39,24 +39,22 @@ const { } = MM_TABLES.SERVER; export interface UserHandlerMix { - handleChannelMembership: ({channelMemberships, prepareRecordsOnly}: HandleChannelMembershipArgs) => Promise; - handlePreferences: ({preferences, prepareRecordsOnly}: HandlePreferencesArgs) => Promise; - handleReactions: ({reactions, prepareRecordsOnly}: HandleReactionsArgs) => Promise>; - handleUsers: ({users, prepareRecordsOnly}: HandleUsersArgs) => Promise; + handleChannelMembership: ({channelMemberships, prepareRecordsOnly}: HandleChannelMembershipArgs) => Promise; + handlePreferences: ({preferences, prepareRecordsOnly}: HandlePreferencesArgs) => Promise; + handleReactions: ({reactions, prepareRecordsOnly}: HandleReactionsArgs) => Promise>; + handleUsers: ({users, prepareRecordsOnly}: HandleUsersArgs) => Promise; } const UserHandler = (superclass: any) => class extends superclass { /** * handleChannelMembership: Handler responsible for the Create/Update operations occurring on the CHANNEL_MEMBERSHIP table from the 'Server' schema * @param {HandleChannelMembershipArgs} channelMembershipsArgs - * @param {RawChannelMembership[]} channelMembershipsArgs.channelMemberships + * @param {ChannelMembership[]} channelMembershipsArgs.channelMemberships * @param {boolean} channelMembershipsArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {Promise} + * @returns {Promise} */ - handleChannelMembership = async ({channelMemberships, prepareRecordsOnly = true}: HandleChannelMembershipArgs) => { - let records: ChannelMembership[] = []; - + handleChannelMembership = ({channelMemberships, prepareRecordsOnly = true}: HandleChannelMembershipArgs): Promise => { if (!channelMemberships.length) { throw new DataOperatorException( 'An empty "channelMemberships" array has been passed to the handleChannelMembership method', @@ -65,7 +63,7 @@ const UserHandler = (superclass: any) => class extends superclass { const createOrUpdateRawValues = getUniqueRawsBy({raws: channelMemberships, key: 'channel_id'}); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'user_id', findMatchingRecordBy: isRecordChannelMembershipEqualToRaw, transformer: transformChannelMembershipRecord, @@ -73,21 +71,17 @@ const UserHandler = (superclass: any) => class extends superclass { createOrUpdateRawValues, tableName: CHANNEL_MEMBERSHIP, }); - - return records; }; /** * handlePreferences: Handler responsible for the Create/Update operations occurring on the PREFERENCE table from the 'Server' schema * @param {HandlePreferencesArgs} preferencesArgs - * @param {RawPreference[]} preferencesArgs.preferences + * @param {PreferenceType[]} preferencesArgs.preferences * @param {boolean} preferencesArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {Promise} + * @returns {Promise} */ - handlePreferences = async ({preferences, prepareRecordsOnly = true}: HandlePreferencesArgs) => { - let records: Preference[] = []; - + handlePreferences = ({preferences, prepareRecordsOnly = true}: HandlePreferencesArgs): Promise => { if (!preferences.length) { throw new DataOperatorException( 'An empty "preferences" array has been passed to the handlePreferences method', @@ -96,7 +90,7 @@ const UserHandler = (superclass: any) => class extends superclass { const createOrUpdateRawValues = getUniqueRawsBy({raws: preferences, key: 'name'}); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'user_id', findMatchingRecordBy: isRecordPreferenceEqualToRaw, transformer: transformPreferenceRecord, @@ -104,20 +98,18 @@ const UserHandler = (superclass: any) => class extends superclass { createOrUpdateRawValues, tableName: PREFERENCE, }); - - return records; }; /** * handleReactions: Handler responsible for the Create/Update operations occurring on the Reaction table from the 'Server' schema * @param {HandleReactionsArgs} handleReactions - * @param {RawReaction[]} handleReactions.reactions + * @param {Reaction[]} handleReactions.reactions * @param {boolean} handleReactions.prepareRecordsOnly * @throws DataOperatorException - * @returns {Promise<(Reaction| CustomEmoji)[]>} + * @returns {Promise>} */ - handleReactions = async ({reactions, prepareRecordsOnly}: HandleReactionsArgs) => { - let batchRecords: Array = []; + handleReactions = async ({reactions, prepareRecordsOnly}: HandleReactionsArgs): Promise> => { + let batchRecords: Array = []; if (!reactions.length) { throw new DataOperatorException( @@ -125,7 +117,7 @@ const UserHandler = (superclass: any) => class extends superclass { ); } - const rawValues = getUniqueRawsBy({raws: reactions, key: 'emoji_name'}) as RawReaction[]; + const rawValues = getUniqueRawsBy({raws: reactions, key: 'emoji_name'}) as Reaction[]; const { createEmojis, @@ -143,7 +135,7 @@ const UserHandler = (superclass: any) => class extends superclass { createRaws: createReactions, transformer: transformReactionRecord, tableName: REACTION, - })) as Reaction[]; + })) as ReactionModel[]; batchRecords = batchRecords.concat(reactionsRecords); } @@ -153,7 +145,7 @@ const UserHandler = (superclass: any) => class extends superclass { createRaws: getRawRecordPairs(createEmojis), transformer: transformCustomEmojiRecord, tableName: CUSTOM_EMOJI, - })) as CustomEmoji[]; + })) as CustomEmojiModel[]; batchRecords = batchRecords.concat(emojiRecords); } @@ -167,20 +159,18 @@ const UserHandler = (superclass: any) => class extends superclass { await this.batchRecords(batchRecords); } - return []; + return batchRecords; }; /** * handleUsers: Handler responsible for the Create/Update operations occurring on the User table from the 'Server' schema * @param {HandleUsersArgs} usersArgs - * @param {RawUser[]} usersArgs.users + * @param {UserProfile[]} usersArgs.users * @param {boolean} usersArgs.prepareRecordsOnly * @throws DataOperatorException - * @returns {Promise} + * @returns {Promise} */ - handleUsers = async ({users, prepareRecordsOnly = true}: HandleUsersArgs) => { - let records: User[] = []; - + handleUsers = async ({users, prepareRecordsOnly = true}: HandleUsersArgs): Promise => { if (!users.length) { throw new DataOperatorException( 'An empty "users" array has been passed to the handleUsers method', @@ -189,7 +179,7 @@ const UserHandler = (superclass: any) => class extends superclass { const createOrUpdateRawValues = getUniqueRawsBy({raws: users, key: 'id'}); - records = await this.handleRecords({ + return this.handleRecords({ fieldName: 'id', findMatchingRecordBy: isRecordUserEqualToRaw, transformer: transformUserRecord, @@ -197,8 +187,6 @@ const UserHandler = (superclass: any) => class extends superclass { tableName: USER, prepareRecordsOnly, }); - - return records; }; }; diff --git a/app/database/operator/server_data_operator/transformers/channel.test.ts b/app/database/operator/server_data_operator/transformers/channel.test.ts index fcb2a8bd45..db9e3d9bd3 100644 --- a/app/database/operator/server_data_operator/transformers/channel.test.ts +++ b/app/database/operator/server_data_operator/transformers/channel.test.ts @@ -38,7 +38,6 @@ describe('*** CHANNEL Prepare Records Test ***', () => { extra_update_at: 0, creator_id: '', scheme_id: null, - props: null, group_constrained: null, shared: null, }, @@ -46,7 +45,7 @@ describe('*** CHANNEL Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords.collection.modelClass.name).toBe('Channel'); + expect(preparedRecords.collection.modelClass.name).toBe('ChannelModel'); }); it('=> transformMyChannelSettingsRecord: should return an array of type MyChannelSettings', async () => { @@ -55,28 +54,34 @@ describe('*** CHANNEL Prepare Records Test ***', () => { const database = await createTestConnection({databaseName: 'channel_prepare_records', setActive: true}); expect(database).toBeTruthy(); + const raw: ChannelMembership = { + channel_id: 'c', + user_id: 'me', + roles: '', + last_viewed_at: 0, + msg_count: 0, + mention_count: 0, + last_update_at: 0, + notify_props: { + desktop: 'default', + email: 'default', + push: 'mention', + mark_unread: 'mention', + ignore_channel_mentions: 'default', + }, + }; + const preparedRecords = await transformMyChannelSettingsRecord({ action: OperationType.CREATE, database: database!, value: { record: undefined, - raw: { - channel_id: 'c', - notify_props: { - desktop: 'all', - desktop_sound: true, - email: true, - first_name: true, - mention_keys: '', - push: 'mention', - channel: true, - }, - }, + raw, }, }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('MyChannelSettings'); + expect(preparedRecords!.collection.modelClass.name).toBe('MyChannelSettingsModel'); }); it('=> transformChannelInfoRecord: should return an array of type ChannelInfo', async () => { @@ -102,7 +107,7 @@ describe('*** CHANNEL Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('ChannelInfo'); + expect(preparedRecords!.collection.modelClass.name).toBe('ChannelInfoModel'); }); it('=> transformMyChannelRecord: should return an array of type MyChannel', async () => { @@ -118,16 +123,19 @@ describe('*** CHANNEL Prepare Records Test ***', () => { record: undefined, raw: { channel_id: 'cd', + user_id: 'guest', last_post_at: 1617311494451, last_viewed_at: 1617311494451, - mentions_count: 3, - message_count: 10, + last_update_at: 0, + mention_count: 3, + msg_count: 10, roles: 'guest', + notify_props: {}, }, }, }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('MyChannel'); + expect(preparedRecords!.collection.modelClass.name).toBe('MyChannelModel'); }); }); diff --git a/app/database/operator/server_data_operator/transformers/channel.ts b/app/database/operator/server_data_operator/transformers/channel.ts index c69996d002..94baaaf8c1 100644 --- a/app/database/operator/server_data_operator/transformers/channel.ts +++ b/app/database/operator/server_data_operator/transformers/channel.ts @@ -3,18 +3,13 @@ import {MM_TABLES} from '@constants/database'; import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index'; -import Channel from '@typings/database/models/servers/channel'; -import ChannelInfo from '@typings/database/models/servers/channel_info'; -import { - TransformerArgs, - RawChannel, - RawChannelInfo, - RawMyChannel, - RawMyChannelSettings, -} from '@typings/database/database'; + +import type ChannelModel from '@typings/database/models/servers/channel'; +import type ChannelInfoModel from '@typings/database/models/servers/channel_info'; +import type {TransformerArgs} from '@typings/database/database'; import {OperationType} from '@typings/database/enums'; -import MyChannel from '@typings/database/models/servers/my_channel'; -import MyChannelSettings from '@typings/database/models/servers/my_channel_settings'; +import type MyChannelModel from '@typings/database/models/servers/my_channel'; +import type MyChannelSettingsModel from '@typings/database/models/servers/my_channel_settings'; const { CHANNEL, @@ -28,15 +23,15 @@ const { * @param {DataFactory} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformChannelRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawChannel; - const record = value.record as Channel; +export const transformChannelRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as Channel; + const record = value.record as ChannelModel; const isCreateAction = action === OperationType.CREATE; // If isCreateAction is true, we will use the id (API response) from the RAW, else we shall use the existing record id from the database - const fieldsMapper = (channel: Channel) => { + const fieldsMapper = (channel: ChannelModel) => { channel._raw.id = isCreateAction ? (raw?.id ?? channel.id) : record.id; channel.createAt = raw.create_at; channel.creatorId = raw.creator_id; @@ -54,7 +49,7 @@ export const transformChannelRecord = ({action, database, value}: TransformerArg tableName: CHANNEL, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -62,14 +57,14 @@ export const transformChannelRecord = ({action, database, value}: TransformerArg * @param {DataFactory} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformMyChannelSettingsRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawMyChannelSettings; - const record = value.record as MyChannelSettings; +export const transformMyChannelSettingsRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as ChannelMembership; + const record = value.record as MyChannelSettingsModel; const isCreateAction = action === OperationType.CREATE; - const fieldsMapper = (myChannelSetting: MyChannelSettings) => { + const fieldsMapper = (myChannelSetting: MyChannelSettingsModel) => { myChannelSetting._raw.id = isCreateAction ? myChannelSetting.id : record.id; myChannelSetting.channelId = raw.channel_id; myChannelSetting.notifyProps = raw.notify_props; @@ -81,7 +76,7 @@ export const transformMyChannelSettingsRecord = ({action, database, value}: Tran tableName: MY_CHANNEL_SETTINGS, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -89,14 +84,14 @@ export const transformMyChannelSettingsRecord = ({action, database, value}: Tran * @param {DataFactory} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformChannelInfoRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawChannelInfo; - const record = value.record as ChannelInfo; +export const transformChannelInfoRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as ChannelInfo; + const record = value.record as ChannelInfoModel; const isCreateAction = action === OperationType.CREATE; - const fieldsMapper = (channelInfo: ChannelInfo) => { + const fieldsMapper = (channelInfo: ChannelInfoModel) => { channelInfo._raw.id = isCreateAction ? channelInfo.id : record.id; channelInfo.channelId = raw.channel_id; channelInfo.guestCount = raw.guest_count; @@ -112,7 +107,7 @@ export const transformChannelInfoRecord = ({action, database, value}: Transforme tableName: CHANNEL_INFO, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -120,20 +115,20 @@ export const transformChannelInfoRecord = ({action, database, value}: Transforme * @param {DataFactory} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformMyChannelRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawMyChannel; - const record = value.record as MyChannel; +export const transformMyChannelRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as ChannelMembership; + const record = value.record as MyChannelModel; const isCreateAction = action === OperationType.CREATE; - const fieldsMapper = (myChannel: MyChannel) => { + const fieldsMapper = (myChannel: MyChannelModel) => { myChannel._raw.id = isCreateAction ? myChannel.id : record.id; myChannel.channelId = raw.channel_id; myChannel.roles = raw.roles; - myChannel.messageCount = raw.message_count; - myChannel.mentionsCount = raw.mentions_count; - myChannel.lastPostAt = raw.last_post_at; + myChannel.messageCount = raw.msg_count; + myChannel.mentionsCount = raw.mention_count; + myChannel.lastPostAt = raw.last_post_at || 0; myChannel.lastViewedAt = raw.last_viewed_at; }; @@ -143,6 +138,6 @@ export const transformMyChannelRecord = ({action, database, value}: TransformerA tableName: MY_CHANNEL, value, fieldsMapper, - }); + }) as Promise; }; diff --git a/app/database/operator/server_data_operator/transformers/general.test.ts b/app/database/operator/server_data_operator/transformers/general.test.ts index e07873c44a..d7474ebdaa 100644 --- a/app/database/operator/server_data_operator/transformers/general.test.ts +++ b/app/database/operator/server_data_operator/transformers/general.test.ts @@ -31,7 +31,7 @@ describe('*** Role Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('Role'); + expect(preparedRecords!.collection.modelClass.name).toBe('RoleModel'); }); }); @@ -52,7 +52,7 @@ describe('*** System Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('System'); + expect(preparedRecords!.collection.modelClass.name).toBe('SystemModel'); }); }); @@ -79,7 +79,7 @@ describe('*** TOS Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('TermsOfService'); + expect(preparedRecords!.collection.modelClass.name).toBe('TermsOfServiceModel'); }); }); @@ -107,7 +107,7 @@ describe('*** CustomEmoj Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('CustomEmoji'); + expect(preparedRecords!.collection.modelClass.name).toBe('CustomEmojiModel'); }); }); diff --git a/app/database/operator/server_data_operator/transformers/general.ts b/app/database/operator/server_data_operator/transformers/general.ts index 77d149d57d..57ac030a94 100644 --- a/app/database/operator/server_data_operator/transformers/general.ts +++ b/app/database/operator/server_data_operator/transformers/general.ts @@ -3,18 +3,13 @@ import {MM_TABLES} from '@constants/database'; import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index'; -import CustomEmoji from '@typings/database/models/servers/custom_emoji'; -import { - TransformerArgs, - RawCustomEmoji, - RawRole, - RawSystem, - RawTermsOfService, -} from '@typings/database/database'; + +import type CustomEmojiModel from '@typings/database/models/servers/custom_emoji'; +import type {TransformerArgs} from '@typings/database/database'; import {OperationType} from '@typings/database/enums'; -import Role from '@typings/database/models/servers/role'; -import System from '@typings/database/models/servers/system'; -import TermsOfService from '@typings/database/models/servers/terms_of_service'; +import type RoleModel from '@typings/database/models/servers/role'; +import type SystemModel from '@typings/database/models/servers/system'; +import type TermsOfServiceModel from '@typings/database/models/servers/terms_of_service'; const { CUSTOM_EMOJI, @@ -28,15 +23,15 @@ const { * @param {TransformerArgs} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformCustomEmojiRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawCustomEmoji; - const record = value.record as CustomEmoji; +export const transformCustomEmojiRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as CustomEmoji; + const record = value.record as CustomEmojiModel; const isCreateAction = action === OperationType.CREATE; // If isCreateAction is true, we will use the id (API response) from the RAW, else we shall use the existing record id from the database - const fieldsMapper = (emoji: CustomEmoji) => { + const fieldsMapper = (emoji: CustomEmojiModel) => { emoji._raw.id = isCreateAction ? (raw?.id ?? emoji.id) : record.id; emoji.name = raw.name; }; @@ -47,7 +42,7 @@ export const transformCustomEmojiRecord = ({action, database, value}: Transforme tableName: CUSTOM_EMOJI, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -55,15 +50,15 @@ export const transformCustomEmojiRecord = ({action, database, value}: Transforme * @param {TransformerArgs} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformRoleRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawRole; - const record = value.record as Role; +export const transformRoleRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as Role; + const record = value.record as RoleModel; const isCreateAction = action === OperationType.CREATE; // If isCreateAction is true, we will use the id (API response) from the RAW, else we shall use the existing record id from the database - const fieldsMapper = (role: Role) => { + const fieldsMapper = (role: RoleModel) => { role._raw.id = isCreateAction ? (raw?.id ?? role.id) : record.id; role.name = raw?.name; role.permissions = raw?.permissions; @@ -75,7 +70,7 @@ export const transformRoleRecord = ({action, database, value}: TransformerArgs) tableName: ROLE, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -83,13 +78,13 @@ export const transformRoleRecord = ({action, database, value}: TransformerArgs) * @param {TransformerArgs} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformSystemRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawSystem; +export const transformSystemRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as IdValue; // If isCreateAction is true, we will use the id (API response) from the RAW, else we shall use the existing record id from the database - const fieldsMapper = (system: System) => { + const fieldsMapper = (system: SystemModel) => { system._raw.id = raw?.id; system.value = raw?.value; }; @@ -100,7 +95,7 @@ export const transformSystemRecord = ({action, database, value}: TransformerArgs tableName: SYSTEM, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -108,15 +103,15 @@ export const transformSystemRecord = ({action, database, value}: TransformerArgs * @param {TransformerArgs} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformTermsOfServiceRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawTermsOfService; - const record = value.record as TermsOfService; +export const transformTermsOfServiceRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as TermsOfService; + const record = value.record as TermsOfServiceModel; const isCreateAction = action === OperationType.CREATE; // If isCreateAction is true, we will use the id (API response) from the RAW, else we shall use the existing record id from the database - const fieldsMapper = (tos: TermsOfService) => { + const fieldsMapper = (tos: TermsOfServiceModel) => { tos._raw.id = isCreateAction ? (raw?.id ?? tos.id) : record.id; tos.acceptedAt = raw?.accepted_at; }; @@ -127,5 +122,5 @@ export const transformTermsOfServiceRecord = ({action, database, value}: Transfo tableName: TERMS_OF_SERVICE, value, fieldsMapper, - }); + }) as Promise; }; diff --git a/app/database/operator/server_data_operator/transformers/group.test.ts b/app/database/operator/server_data_operator/transformers/group.test.ts index b39d4dc64a..b58404e77a 100644 --- a/app/database/operator/server_data_operator/transformers/group.test.ts +++ b/app/database/operator/server_data_operator/transformers/group.test.ts @@ -27,18 +27,20 @@ describe('*** GROUP Prepare Records Test ***', () => { name: 'mobile_team', display_name: 'mobile team', description: '', - source: '', + type: '', remote_id: '', create_at: 0, update_at: 0, delete_at: 0, has_syncables: true, + member_count: 0, + allow_reference: false, }, }, }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('Group'); + expect(preparedRecords!.collection.modelClass.name).toBe('GroupModel'); }); it('=> transformGroupsInTeamRecord: should return an array of type GroupsInTeam', async () => { @@ -66,7 +68,7 @@ describe('*** GROUP Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('GroupsInTeam'); + expect(preparedRecords!.collection.modelClass.name).toBe('GroupsInTeamModel'); }); it('=> transformGroupsInChannelRecord: should return an array of type GroupsInChannel', async () => { @@ -97,7 +99,7 @@ describe('*** GROUP Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('GroupsInChannel'); + expect(preparedRecords!.collection.modelClass.name).toBe('GroupsInChannelModel'); }); it('=> transformGroupMembershipRecord: should return an array of type GroupMembership', async () => { @@ -119,6 +121,6 @@ describe('*** GROUP Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('GroupMembership'); + expect(preparedRecords!.collection.modelClass.name).toBe('GroupMembershipModel'); }); }); diff --git a/app/database/operator/server_data_operator/transformers/group.ts b/app/database/operator/server_data_operator/transformers/group.ts index 9e12a48984..52c87b6377 100644 --- a/app/database/operator/server_data_operator/transformers/group.ts +++ b/app/database/operator/server_data_operator/transformers/group.ts @@ -3,18 +3,13 @@ import {MM_TABLES} from '@constants/database'; import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index'; -import { - TransformerArgs, - RawGroup, - RawGroupMembership, - RawGroupsInChannel, - RawGroupsInTeam, -} from '@typings/database/database'; + +import type {TransformerArgs} from '@typings/database/database'; import {OperationType} from '@typings/database/enums'; -import Group from '@typings/database/models/servers/group'; -import GroupMembership from '@typings/database/models/servers/group_membership'; -import GroupsInChannel from '@typings/database/models/servers/groups_in_channel'; -import GroupsInTeam from '@typings/database/models/servers/groups_in_team'; +import type GroupModel from '@typings/database/models/servers/group'; +import type GroupMembershipModel from '@typings/database/models/servers/group_membership'; +import type GroupsInChannelModel from '@typings/database/models/servers/groups_in_channel'; +import type GroupsInTeamModel from '@typings/database/models/servers/groups_in_team'; const { GROUP, @@ -28,15 +23,15 @@ const { * @param {TransformerArgs} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformGroupMembershipRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawGroupMembership; - const record = value.record as GroupMembership; +export const transformGroupMembershipRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as GroupMembership; + const record = value.record as GroupMembershipModel; const isCreateAction = action === OperationType.CREATE; // If isCreateAction is true, we will use the id (API response) from the RAW, else we shall use the existing record id from the database - const fieldsMapper = (groupMember: GroupMembership) => { + const fieldsMapper = (groupMember: GroupMembershipModel) => { groupMember._raw.id = isCreateAction ? (raw?.id ?? groupMember.id) : record.id; groupMember.groupId = raw.group_id; groupMember.userId = raw.user_id; @@ -48,7 +43,7 @@ export const transformGroupMembershipRecord = ({action, database, value}: Transf tableName: GROUP_MEMBERSHIP, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -56,15 +51,15 @@ export const transformGroupMembershipRecord = ({action, database, value}: Transf * @param {DataFactory} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformGroupRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawGroup; - const record = value.record as Group; +export const transformGroupRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as Group; + const record = value.record as GroupModel; const isCreateAction = action === OperationType.CREATE; // If isCreateAction is true, we will use the id (API response) from the RAW, else we shall use the existing record id from the database - const fieldsMapper = (group: Group) => { + const fieldsMapper = (group: GroupModel) => { group._raw.id = isCreateAction ? (raw?.id ?? group.id) : record.id; group.name = raw.name; group.displayName = raw.display_name; @@ -76,7 +71,7 @@ export const transformGroupRecord = ({action, database, value}: TransformerArgs) tableName: GROUP, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -84,14 +79,14 @@ export const transformGroupRecord = ({action, database, value}: TransformerArgs) * @param {DataFactory} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformGroupsInTeamRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawGroupsInTeam; - const record = value.record as GroupsInTeam; +export const transformGroupsInTeamRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as GroupTeam; + const record = value.record as GroupsInTeamModel; const isCreateAction = action === OperationType.CREATE; - const fieldsMapper = (groupsInTeam: GroupsInTeam) => { + const fieldsMapper = (groupsInTeam: GroupsInTeamModel) => { groupsInTeam._raw.id = isCreateAction ? groupsInTeam.id : record.id; groupsInTeam.teamId = raw.team_id; groupsInTeam.groupId = raw.group_id; @@ -103,7 +98,7 @@ export const transformGroupsInTeamRecord = ({action, database, value}: Transform tableName: GROUPS_IN_TEAM, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -111,14 +106,14 @@ export const transformGroupsInTeamRecord = ({action, database, value}: Transform * @param {DataFactory} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformGroupsInChannelRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawGroupsInChannel; - const record = value.record as GroupsInChannel; +export const transformGroupsInChannelRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as GroupChannel; + const record = value.record as GroupsInChannelModel; const isCreateAction = action === OperationType.CREATE; - const fieldsMapper = (groupsInChannel: GroupsInChannel) => { + const fieldsMapper = (groupsInChannel: GroupsInChannelModel) => { groupsInChannel._raw.id = isCreateAction ? groupsInChannel.id : record.id; groupsInChannel.channelId = raw.channel_id; groupsInChannel.groupId = raw.group_id; @@ -132,5 +127,5 @@ export const transformGroupsInChannelRecord = ({action, database, value}: Transf tableName: GROUPS_IN_CHANNEL, value, fieldsMapper, - }); + }) as Promise; }; diff --git a/app/database/operator/server_data_operator/transformers/post.test.ts b/app/database/operator/server_data_operator/transformers/post.test.ts index a2b7c7e846..62f51a0ce9 100644 --- a/app/database/operator/server_data_operator/transformers/post.test.ts +++ b/app/database/operator/server_data_operator/transformers/post.test.ts @@ -50,7 +50,7 @@ describe('*** POST Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('Post'); + expect(preparedRecords!.collection.modelClass.name).toBe('PostModel'); }); it('=> transformPostInThreadRecord: should return an array of type PostsInThread', async () => { @@ -75,7 +75,7 @@ describe('*** POST Prepare Records Test ***', () => { expect(preparedRecords).toBeTruthy(); expect(preparedRecords!.collection.modelClass.name).toBe( - 'PostsInThread', + 'PostsInThreadModel', ); }); @@ -91,13 +91,17 @@ describe('*** POST Prepare Records Test ***', () => { value: { record: undefined, raw: { + id: 'file-id', post_id: 'ps81iqbddesfby8jayz7owg4yypoo', name: 'test_file', extension: '.jpg', + has_preview_image: true, + mime_type: 'image/jpeg', size: 1000, create_at: 1609253011321, delete_at: 1609253011321, height: 20, + width: 20, update_at: 1609253011321, user_id: 'wqyby5r5pinxxdqhoaomtacdhc', }, @@ -105,7 +109,7 @@ describe('*** POST Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('File'); + expect(preparedRecords!.collection.modelClass.name).toBe('FileModel'); }); it('=> transformPostMetadataRecord: should return an array of type PostMetadata', async () => { @@ -121,15 +125,33 @@ describe('*** POST Prepare Records Test ***', () => { record: undefined, raw: { id: 'ps81i4yypoo', - data: {}, - postId: 'ps81iqbddesfby8jayz7owg4yypoo', - type: 'opengraph', + data: { + files: [ + { + id: 'mjagj4ta4tb93f7mwdn68yw9rc', + user_id: 'gy5cnn5q9i8txdkcrj4dhntnta', + post_id: '4wpufe8d5pd7jpwshzrumgjd7r', + create_at: 1626207675617, + update_at: 1626207675617, + delete_at: 0, + name: 'Image Pasted at 2021-7-13 22-21.png', + extension: 'png', + size: 4668, + mime_type: 'image/png', + width: 67, + height: 116, + has_preview_image: true, + mini_preview: '/9j/2wCEAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRQBAwQEBQQFCQUFCRQNCw0UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFP/AABEIABAAEAMBIgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/APPv2c/gr8O/GvwHbWNW0CDW/Elxd6nbS3janMH090jj+xK1tDIHEUhZy0wjl27ANpDZXhP2kvgzo3wk8OeDjZPpbahfXE8bm2kdbqWKOOIieWFpXMSs7yKoYKxCZIGcCz+zvB8J5vD98vjIacmutFCLGfV4XlsIzvfzjKsfzmTGzAY7dp45zXjvirV9I1LXdRW4gXw7GLib7Iuh6J59uyo22IqWnDhZASzZ6bVwOTjuelS7vockKr9m4RUdd9r6equvkz//2Q==', + }, + ], + }, + post_id: 'ps81iqbddesfby8jayz7owg4yypoo', }, }, }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('PostMetadata'); + expect(preparedRecords!.collection.modelClass.name).toBe('PostMetadataModel'); }); it('=> transformDraftRecord: should return an array of type Draft', async () => { @@ -154,7 +176,7 @@ describe('*** POST Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('Draft'); + expect(preparedRecords!.collection.modelClass.name).toBe('DraftModel'); }); it('=> transformPostsInChannelRecord: should return an array of type PostsInChannel', async () => { @@ -179,7 +201,7 @@ describe('*** POST Prepare Records Test ***', () => { expect(preparedRecords).toBeTruthy(); expect(preparedRecords!.collection.modelClass.name).toBe( - 'PostsInChannel', + 'PostsInChannelModel', ); }); }); diff --git a/app/database/operator/server_data_operator/transformers/post.ts b/app/database/operator/server_data_operator/transformers/post.ts index 7ba03d2ce0..39f382aefc 100644 --- a/app/database/operator/server_data_operator/transformers/post.ts +++ b/app/database/operator/server_data_operator/transformers/post.ts @@ -4,22 +4,15 @@ import {Q} from '@nozbe/watermelondb'; import {MM_TABLES} from '@constants/database'; import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index'; -import type{ - TransformerArgs, - RawDraft, - RawFile, - RawPost, - RawPostMetadata, - RawPostsInChannel, - RawPostsInThread, -} from '@typings/database/database'; -import Draft from '@typings/database/models/servers/draft'; + +import type{TransformerArgs} from '@typings/database/database'; +import type DraftModel from '@typings/database/models/servers/draft'; import {OperationType} from '@typings/database/enums'; -import File from '@typings/database/models/servers/file'; -import Post from '@typings/database/models/servers/post'; -import PostMetadata from '@typings/database/models/servers/post_metadata'; -import PostsInChannel from '@typings/database/models/servers/posts_in_channel'; -import PostsInThread from '@typings/database/models/servers/posts_in_thread'; +import type FileModel from '@typings/database/models/servers/file'; +import type PostModel from '@typings/database/models/servers/post'; +import type PostMetadataModel from '@typings/database/models/servers/post_metadata'; +import type PostsInChannelModel from '@typings/database/models/servers/posts_in_channel'; +import type PostsInThreadModel from '@typings/database/models/servers/posts_in_thread'; const { DRAFT, @@ -35,15 +28,15 @@ const { * @param {TransformerArgs} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformPostRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawPost; - const record = value.record as Post; +export const transformPostRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as Post; + const record = value.record as PostModel; const isCreateAction = action === OperationType.CREATE; // If isCreateAction is true, we will use the id (API response) from the RAW, else we shall use the existing record id from the database - const fieldsMapper = (post: Post) => { + const fieldsMapper = (post: PostModel) => { post._raw.id = isCreateAction ? (raw?.id ?? post.id) : record.id; post.channelId = raw.channel_id; post.createAt = raw.create_at; @@ -67,7 +60,7 @@ export const transformPostRecord = ({action, database, value}: TransformerArgs) tableName: POST, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -75,14 +68,14 @@ export const transformPostRecord = ({action, database, value}: TransformerArgs) * @param {TransformerArgs} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformPostInThreadRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawPostsInThread; - const record = value.record as PostsInThread; +export const transformPostInThreadRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as PostsInThread; + const record = value.record as PostsInThreadModel; const isCreateAction = action === OperationType.CREATE; - const fieldsMapper = (postsInThread: PostsInThread) => { + const fieldsMapper = (postsInThread: PostsInThreadModel) => { postsInThread.postId = isCreateAction ? raw.post_id : record.id; postsInThread.earliest = raw.earliest; postsInThread.latest = raw.latest!; @@ -94,7 +87,7 @@ export const transformPostInThreadRecord = ({action, database, value}: Transform tableName: POSTS_IN_THREAD, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -102,15 +95,15 @@ export const transformPostInThreadRecord = ({action, database, value}: Transform * @param {TransformerArgs} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformFileRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawFile; - const record = value.record as File; +export const transformFileRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as FileInfo; + const record = value.record as FileModel; const isCreateAction = action === OperationType.CREATE; // If isCreateAction is true, we will use the id (API response) from the RAW, else we shall use the existing record id from the database - const fieldsMapper = (file: File) => { + const fieldsMapper = (file: FileModel) => { file._raw.id = isCreateAction ? (raw?.id ?? file.id) : record.id; file.postId = raw.post_id; file.name = raw.name; @@ -129,7 +122,7 @@ export const transformFileRecord = ({action, database, value}: TransformerArgs) tableName: FILE, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -137,18 +130,17 @@ export const transformFileRecord = ({action, database, value}: TransformerArgs) * @param {TransformerArgs} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformPostMetadataRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawPostMetadata; - const record = value.record as PostMetadata; +export const transformPostMetadataRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as Metadata; + const record = value.record as PostMetadataModel; const isCreateAction = action === OperationType.CREATE; - const fieldsMapper = (postMeta: PostMetadata) => { + const fieldsMapper = (postMeta: PostMetadataModel) => { postMeta._raw.id = isCreateAction ? postMeta.id : record.id; postMeta.data = raw.data; - postMeta.postId = raw.postId; - postMeta.type = raw.type; + postMeta.postId = raw.post_id; }; return prepareBaseRecord({ @@ -157,7 +149,7 @@ export const transformPostMetadataRecord = ({action, database, value}: Transform tableName: POST_METADATA, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -165,14 +157,14 @@ export const transformPostMetadataRecord = ({action, database, value}: Transform * @param {TransformerArgs} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformDraftRecord = ({action, database, value}: TransformerArgs) => { +export const transformDraftRecord = ({action, database, value}: TransformerArgs): Promise => { const emptyFileInfo: FileInfo[] = []; - const raw = value.raw as RawDraft; + const raw = value.raw as Draft; // We use the raw id as Draft is client side only and we would only be creating/deleting drafts - const fieldsMapper = (draft: Draft) => { + const fieldsMapper = (draft: DraftModel) => { draft._raw.id = draft.id; draft.rootId = raw?.root_id ?? ''; draft.message = raw?.message ?? ''; @@ -186,7 +178,7 @@ export const transformDraftRecord = ({action, database, value}: TransformerArgs) tableName: DRAFT, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -194,14 +186,14 @@ export const transformDraftRecord = ({action, database, value}: TransformerArgs) * @param {TransformerArgs} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformPostsInChannelRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawPostsInChannel; - const record = value.record as PostsInChannel; +export const transformPostsInChannelRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as PostsInChannel; + const record = value.record as PostsInChannelModel; const isCreateAction = action === OperationType.CREATE; - const fieldsMapper = (postsInChannel: PostsInChannel) => { + const fieldsMapper = (postsInChannel: PostsInChannelModel) => { postsInChannel._raw.id = isCreateAction ? postsInChannel.id : record.id; postsInChannel.channelId = raw.channel_id; postsInChannel.earliest = raw.earliest; @@ -214,5 +206,5 @@ export const transformPostsInChannelRecord = ({action, database, value}: Transfo tableName: POSTS_IN_CHANNEL, value, fieldsMapper, - }); + }) as Promise; }; diff --git a/app/database/operator/server_data_operator/transformers/team.test.ts b/app/database/operator/server_data_operator/transformers/team.test.ts index 838b2bfaa1..c17246d60a 100644 --- a/app/database/operator/server_data_operator/transformers/team.test.ts +++ b/app/database/operator/server_data_operator/transformers/team.test.ts @@ -47,7 +47,7 @@ describe('*** TEAM Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('SlashCommand'); + expect(preparedRecords!.collection.modelClass.name).toBe('SlashCommandModel'); }); it('=> transformMyTeamRecord: should return an array of type MyTeam', async () => { @@ -71,7 +71,7 @@ describe('*** TEAM Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('MyTeam'); + expect(preparedRecords!.collection.modelClass.name).toBe('MyTeamModel'); }); it('=> transformTeamRecord: should return an array of type Team', async () => { @@ -107,7 +107,7 @@ describe('*** TEAM Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('Team'); + expect(preparedRecords!.collection.modelClass.name).toBe('TeamModel'); }); it('=> transformTeamChannelHistoryRecord: should return an array of type Team', async () => { @@ -129,7 +129,7 @@ describe('*** TEAM Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('TeamChannelHistory'); + expect(preparedRecords!.collection.modelClass.name).toBe('TeamChannelHistoryModel'); }); it('=> transformTeamSearchHistoryRecord: should return an array of type TeamSearchHistory', async () => { @@ -153,7 +153,7 @@ describe('*** TEAM Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('TeamSearchHistory'); + expect(preparedRecords!.collection.modelClass.name).toBe('TeamSearchHistoryModel'); }); it('=> transformTeamMembershipRecord: should return an array of type TeamMembership', async () => { @@ -172,15 +172,15 @@ describe('*** TEAM Prepare Records Test ***', () => { user_id: 'ab', roles: '3ngdqe1e7tfcbmam4qgnxp91bw', delete_at: 0, - scheme_guest: false, scheme_user: true, scheme_admin: false, - explicit_roles: '', + msg_count: 0, + mention_count: 0, }, }, }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('TeamMembership'); + expect(preparedRecords!.collection.modelClass.name).toBe('TeamMembershipModel'); }); }); diff --git a/app/database/operator/server_data_operator/transformers/team.ts b/app/database/operator/server_data_operator/transformers/team.ts index 9f24dad356..d6fc1506b1 100644 --- a/app/database/operator/server_data_operator/transformers/team.ts +++ b/app/database/operator/server_data_operator/transformers/team.ts @@ -4,22 +4,14 @@ import {MM_TABLES} from '@constants/database'; import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index'; -import type { - TransformerArgs, - RawMyTeam, - RawSlashCommand, - RawTeam, - RawTeamChannelHistory, - RawTeamMembership, - RawTeamSearchHistory, -} from '@typings/database/database'; +import type {TransformerArgs} from '@typings/database/database'; import {OperationType} from '@typings/database/enums'; -import MyTeam from '@typings/database/models/servers/my_team'; -import SlashCommand from '@typings/database/models/servers/slash_command'; -import Team from '@typings/database/models/servers/team'; -import TeamChannelHistory from '@typings/database/models/servers/team_channel_history'; -import TeamMembership from '@typings/database/models/servers/team_membership'; -import TeamSearchHistory from '@typings/database/models/servers/team_search_history'; +import type MyTeamModel from '@typings/database/models/servers/my_team'; +import type SlashCommandModel from '@typings/database/models/servers/slash_command'; +import type TeamModel from '@typings/database/models/servers/team'; +import type TeamChannelHistoryModel from '@typings/database/models/servers/team_channel_history'; +import type TeamMembershipModel from '@typings/database/models/servers/team_membership'; +import type TeamSearchHistoryModel from '@typings/database/models/servers/team_search_history'; const { MY_TEAM, @@ -35,15 +27,15 @@ const { * @param {TransformerArgs} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformTeamMembershipRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawTeamMembership; - const record = value.record as TeamMembership; +export const transformTeamMembershipRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as TeamMembership; + const record = value.record as TeamMembershipModel; const isCreateAction = action === OperationType.CREATE; // If isCreateAction is true, we will use the id (API response) from the RAW, else we shall use the existing record id from the database - const fieldsMapper = (teamMembership: TeamMembership) => { + const fieldsMapper = (teamMembership: TeamMembershipModel) => { teamMembership._raw.id = isCreateAction ? (raw?.id ?? teamMembership.id) : record.id; teamMembership.teamId = raw.team_id; teamMembership.userId = raw.user_id; @@ -55,7 +47,7 @@ export const transformTeamMembershipRecord = ({action, database, value}: Transfo tableName: TEAM_MEMBERSHIP, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -63,15 +55,15 @@ export const transformTeamMembershipRecord = ({action, database, value}: Transfo * @param {DataFactory} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformTeamRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawTeam; - const record = value.record as Team; +export const transformTeamRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as Team; + const record = value.record as TeamModel; const isCreateAction = action === OperationType.CREATE; // If isCreateAction is true, we will use the id (API response) from the RAW, else we shall use the existing record id from the database - const fieldsMapper = (team: Team) => { + const fieldsMapper = (team: TeamModel) => { team._raw.id = isCreateAction ? (raw?.id ?? team.id) : record.id; team.isAllowOpenInvite = raw.allow_open_invite; team.description = raw.description; @@ -90,7 +82,7 @@ export const transformTeamRecord = ({action, database, value}: TransformerArgs) tableName: TEAM, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -98,14 +90,14 @@ export const transformTeamRecord = ({action, database, value}: TransformerArgs) * @param {DataFactory} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformTeamChannelHistoryRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawTeamChannelHistory; - const record = value.record as TeamChannelHistory; +export const transformTeamChannelHistoryRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as TeamChannelHistory; + const record = value.record as TeamChannelHistoryModel; const isCreateAction = action === OperationType.CREATE; - const fieldsMapper = (teamChannelHistory: TeamChannelHistory) => { + const fieldsMapper = (teamChannelHistory: TeamChannelHistoryModel) => { teamChannelHistory._raw.id = isCreateAction ? (teamChannelHistory.id) : record.id; teamChannelHistory.teamId = raw.team_id; teamChannelHistory.channelIds = raw.channel_ids; @@ -117,7 +109,7 @@ export const transformTeamChannelHistoryRecord = ({action, database, value}: Tra tableName: TEAM_CHANNEL_HISTORY, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -125,14 +117,14 @@ export const transformTeamChannelHistoryRecord = ({action, database, value}: Tra * @param {DataFactory} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformTeamSearchHistoryRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawTeamSearchHistory; - const record = value.record as TeamSearchHistory; +export const transformTeamSearchHistoryRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as TeamSearchHistory; + const record = value.record as TeamSearchHistoryModel; const isCreateAction = action === OperationType.CREATE; - const fieldsMapper = (teamSearchHistory: TeamSearchHistory) => { + const fieldsMapper = (teamSearchHistory: TeamSearchHistoryModel) => { teamSearchHistory._raw.id = isCreateAction ? (teamSearchHistory.id) : record.id; teamSearchHistory.createdAt = raw.created_at; teamSearchHistory.displayTerm = raw.display_term; @@ -146,7 +138,7 @@ export const transformTeamSearchHistoryRecord = ({action, database, value}: Tran tableName: TEAM_SEARCH_HISTORY, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -154,15 +146,15 @@ export const transformTeamSearchHistoryRecord = ({action, database, value}: Tran * @param {DataFactory} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformSlashCommandRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawSlashCommand; - const record = value.record as SlashCommand; +export const transformSlashCommandRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as SlashCommand; + const record = value.record as SlashCommandModel; const isCreateAction = action === OperationType.CREATE; // If isCreateAction is true, we will use the id (API response) from the RAW, else we shall use the existing record id from the database - const fieldsMapper = (slashCommand: SlashCommand) => { + const fieldsMapper = (slashCommand: SlashCommandModel) => { slashCommand._raw.id = isCreateAction ? (raw?.id ?? slashCommand.id) : record.id; slashCommand.isAutoComplete = raw.auto_complete; slashCommand.description = raw.description; @@ -181,7 +173,7 @@ export const transformSlashCommandRecord = ({action, database, value}: Transform tableName: SLASH_COMMAND, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -189,14 +181,14 @@ export const transformSlashCommandRecord = ({action, database, value}: Transform * @param {DataFactory} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformMyTeamRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawMyTeam; - const record = value.record as MyTeam; +export const transformMyTeamRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as MyTeam; + const record = value.record as MyTeamModel; const isCreateAction = action === OperationType.CREATE; - const fieldsMapper = (myTeam: MyTeam) => { + const fieldsMapper = (myTeam: MyTeamModel) => { myTeam._raw.id = isCreateAction ? myTeam.id : record.id; myTeam.teamId = raw.team_id; myTeam.roles = raw.roles; @@ -210,5 +202,5 @@ export const transformMyTeamRecord = ({action, database, value}: TransformerArgs tableName: MY_TEAM, value, fieldsMapper, - }); + }) as Promise; }; diff --git a/app/database/operator/server_data_operator/transformers/user.test.ts b/app/database/operator/server_data_operator/transformers/user.test.ts index 690e8c58de..adc76e4de4 100644 --- a/app/database/operator/server_data_operator/transformers/user.test.ts +++ b/app/database/operator/server_data_operator/transformers/user.test.ts @@ -38,16 +38,14 @@ describe('*** USER Prepare Records Test ***', () => { push: 'default', }, last_update_at: 1613667352029, - scheme_guest: false, scheme_user: true, scheme_admin: false, - explicit_roles: '', }, }, }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('ChannelMembership'); + expect(preparedRecords!.collection.modelClass.name).toBe('ChannelMembershipModel'); }); it('=> transformPreferenceRecord: should return an array of type Preference', async () => { @@ -66,7 +64,7 @@ describe('*** USER Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('Preference'); + expect(preparedRecords!.collection.modelClass.name).toBe('PreferenceModel'); }); it('=> transformReactionRecord: should return an array of type Reaction', async () => { @@ -93,7 +91,7 @@ describe('*** USER Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('Reaction'); + expect(preparedRecords!.collection.modelClass.name).toBe('ReactionModel'); }); it('=> transformUserRecord: should return an array of type User', async () => { @@ -114,9 +112,8 @@ describe('*** USER Prepare Records Test ***', () => { update_at: 1607683720173, delete_at: 0, username: 'a.l', - auth_service: 'saml', + auth_service: '', email: 'a.l@mattermost.com', - email_verified: true, nickname: '', first_name: 'A', last_name: 'L', @@ -125,19 +122,19 @@ describe('*** USER Prepare Records Test ***', () => { props: {}, notify_props: { desktop: 'all', - desktop_sound: true, - email: true, - first_name: true, + desktop_sound: 'true', + email: 'true', + first_name: 'true', mention_keys: '', + mark_unread: 'mention', push: 'mention', - channel: true, - auto_responder_active: false, + channel: 'true', + auto_responder_active: 'false', auto_responder_message: 'Hello, I am out of office and unable to respond to messages.', comments: 'never', desktop_notification_sound: 'Hello', push_status: 'online', }, - last_password_update: 1604323112537, last_picture_update: 1604686302260, locale: 'en', timezone: { @@ -150,6 +147,6 @@ describe('*** USER Prepare Records Test ***', () => { }); expect(preparedRecords).toBeTruthy(); - expect(preparedRecords!.collection.modelClass.name).toBe('User'); + expect(preparedRecords!.collection.modelClass.name).toBe('UserModel'); }); }); diff --git a/app/database/operator/server_data_operator/transformers/user.ts b/app/database/operator/server_data_operator/transformers/user.ts index a7c85b8bd5..67def408c7 100644 --- a/app/database/operator/server_data_operator/transformers/user.ts +++ b/app/database/operator/server_data_operator/transformers/user.ts @@ -3,12 +3,13 @@ import {MM_TABLES} from '@constants/database'; import {prepareBaseRecord} from '@database/operator/server_data_operator/transformers/index'; -import ChannelMembership from '@typings/database/models/servers/channel_membership'; -import {TransformerArgs, RawChannelMembership, RawPreference, RawReaction, RawUser} from '@typings/database/database'; + +import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership'; +import type {TransformerArgs} from '@typings/database/database'; import {OperationType} from '@typings/database/enums'; -import Preference from '@typings/database/models/servers/preference'; -import Reaction from '@typings/database/models/servers/reaction'; -import User from '@typings/database/models/servers/user'; +import type PreferenceModel from '@typings/database/models/servers/preference'; +import type ReactionModel from '@typings/database/models/servers/reaction'; +import type UserModel from '@typings/database/models/servers/user'; const { CHANNEL_MEMBERSHIP, @@ -22,15 +23,15 @@ const { * @param {TransformerArgs} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformReactionRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawReaction; - const record = value.record as Reaction; +export const transformReactionRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as Reaction; + const record = value.record as ReactionModel; const isCreateAction = action === OperationType.CREATE; // id of reaction comes from server response - const fieldsMapper = (reaction: Reaction) => { + const fieldsMapper = (reaction: ReactionModel) => { reaction._raw.id = isCreateAction ? (raw?.id ?? reaction.id) : record.id; reaction.userId = raw.user_id; reaction.postId = raw.post_id; @@ -44,7 +45,7 @@ export const transformReactionRecord = ({action, database, value}: TransformerAr tableName: REACTION, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -52,15 +53,15 @@ export const transformReactionRecord = ({action, database, value}: TransformerAr * @param {TransformerArgs} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformUserRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawUser; - const record = value.record as User; +export const transformUserRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as UserProfile; + const record = value.record as UserModel; const isCreateAction = action === OperationType.CREATE; // id of user comes from server response - const fieldsMapper = (user: User) => { + const fieldsMapper = (user: UserModel) => { user._raw.id = isCreateAction ? (raw?.id ?? user.id) : record.id; user.authService = raw.auth_service; user.deleteAt = raw.delete_at; @@ -76,8 +77,8 @@ export const transformUserRecord = ({action, database, value}: TransformerArgs) user.roles = raw.roles; user.username = raw.username; user.notifyProps = raw.notify_props; - user.props = raw.props; - user.timezone = raw.timezone; + user.props = raw.props || null; + user.timezone = raw.timezone || null; user.isBot = raw.is_bot; }; @@ -87,7 +88,7 @@ export const transformUserRecord = ({action, database, value}: TransformerArgs) tableName: USER, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -95,15 +96,15 @@ export const transformUserRecord = ({action, database, value}: TransformerArgs) * @param {TransformerArgs} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformPreferenceRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawPreference; - const record = value.record as Preference; +export const transformPreferenceRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as PreferenceType; + const record = value.record as PreferenceModel; const isCreateAction = action === OperationType.CREATE; // id of preference comes from server response - const fieldsMapper = (preference: Preference) => { + const fieldsMapper = (preference: PreferenceModel) => { preference._raw.id = isCreateAction ? preference.id : record.id; preference.category = raw.category; preference.name = raw.name; @@ -117,7 +118,7 @@ export const transformPreferenceRecord = ({action, database, value}: Transformer tableName: PREFERENCE, value, fieldsMapper, - }); + }) as Promise; }; /** @@ -125,15 +126,15 @@ export const transformPreferenceRecord = ({action, database, value}: Transformer * @param {TransformerArgs} operator * @param {Database} operator.database * @param {RecordPair} operator.value - * @returns {Promise} + * @returns {Promise} */ -export const transformChannelMembershipRecord = ({action, database, value}: TransformerArgs) => { - const raw = value.raw as RawChannelMembership; - const record = value.record as ChannelMembership; +export const transformChannelMembershipRecord = ({action, database, value}: TransformerArgs): Promise => { + const raw = value.raw as ChannelMembership; + const record = value.record as ChannelMembershipModel; const isCreateAction = action === OperationType.CREATE; // If isCreateAction is true, we will use the id (API response) from the RAW, else we shall use the existing record id from the database - const fieldsMapper = (channelMember: ChannelMembership) => { + const fieldsMapper = (channelMember: ChannelMembershipModel) => { channelMember._raw.id = isCreateAction ? (raw?.id ?? channelMember.id) : record.id; channelMember.channelId = raw.channel_id; channelMember.userId = raw.user_id; @@ -145,5 +146,5 @@ export const transformChannelMembershipRecord = ({action, database, value}: Tran tableName: CHANNEL_MEMBERSHIP, value, fieldsMapper, - }); + }) as Promise; }; diff --git a/app/database/operator/utils/general.ts b/app/database/operator/utils/general.ts index 3bfdcee78b..697d3f7c52 100644 --- a/app/database/operator/utils/general.ts +++ b/app/database/operator/utils/general.ts @@ -2,23 +2,13 @@ // See LICENSE.txt for license information. import {MM_TABLES} from '@constants/database'; -import Channel from '@typings/database/models/servers/channel'; -import { - IdenticalRecordArgs, - RangeOfValueArgs, - RawChannel, - RawPost, - RawSlashCommand, - RawTeam, - RawUser, - RawValue, - RecordPair, - RetrieveRecordsArgs, -} from '@typings/database/database'; -import Post from '@typings/database/models/servers/post'; -import SlashCommand from '@typings/database/models/servers/slash_command'; -import Team from '@typings/database/models/servers/team'; -import User from '@typings/database/models/servers/user'; + +import type ChannelModel from '@typings/database/models/servers/channel'; +import type {IdenticalRecordArgs, RangeOfValueArgs, RecordPair, RetrieveRecordsArgs} from '@typings/database/database'; +import type PostModel from '@typings/database/models/servers/post'; +import type SlashCommandModel from '@typings/database/models/servers/slash_command'; +import type TeamModel from '@typings/database/models/servers/team'; +import type UserModel from '@typings/database/models/servers/user'; const {CHANNEL, POST, SLASH_COMMAND, TEAM, USER} = MM_TABLES.SERVER; @@ -34,8 +24,8 @@ const {CHANNEL, POST, SLASH_COMMAND, TEAM, USER} = MM_TABLES.SERVER; export const getValidRecordsForUpdate = ({tableName, newValue, existingRecord}: IdenticalRecordArgs) => { const guardTables = [CHANNEL, POST, SLASH_COMMAND, TEAM, USER]; if (guardTables.includes(tableName)) { - type Raw = RawPost | RawUser | RawTeam | RawSlashCommand | RawChannel; - type ExistingRecord = Post | User | Team | SlashCommand | Channel; + type Raw = Post | UserProfile | Team | SlashCommand | Channel; + type ExistingRecord = PostModel | UserModel | TeamModel | SlashCommandModel | ChannelModel; const shouldUpdate = (newValue as Raw).update_at === (existingRecord as ExistingRecord).updateAt; diff --git a/app/database/operator/utils/post.ts b/app/database/operator/utils/post.ts index ca07c9bb83..82d37b5539 100644 --- a/app/database/operator/utils/post.ts +++ b/app/database/operator/utils/post.ts @@ -1,18 +1,18 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import {ChainPostsArgs, RawPost, RecordPair, SanitizePostsArgs} from '@typings/database/database'; +import type {ChainPostsArgs, RecordPair, SanitizePostsArgs} from '@typings/database/database'; /** * sanitizePosts: Creates arrays of ordered and unordered posts. Unordered posts are those posts that are not * present in the orders array * @param {SanitizePostsArgs} sanitizePosts - * @param {RawPost[]} sanitizePosts.posts + * @param {Post[]} sanitizePosts.posts * @param {string[]} sanitizePosts.orders */ export const sanitizePosts = ({posts, orders}: SanitizePostsArgs) => { - const orderedPosts: RawPost[] = []; - const unOrderedPosts: RawPost[] = []; + const orderedPosts: Post[] = []; + const unOrderedPosts: Post[] = []; posts.forEach((post) => { if (post?.id && orders.includes(post.id)) { @@ -33,9 +33,9 @@ export const sanitizePosts = ({posts, orders}: SanitizePostsArgs) => { * by the previous_post_id field. * @param {ChainPostsArgs} chainPosts * @param {string[]} chainPosts.orders - * @param {RawPost[]} chainPosts.rawPosts + * @param {Post[]} chainPosts.rawPosts * @param {string} chainPosts.previousPostId - * @returns {RawPost[]} + * @returns {Post[]} */ export const createPostsChain = ({orders, rawPosts, previousPostId = ''}: ChainPostsArgs) => { const posts: RecordPair[] = []; diff --git a/app/database/operator/utils/reaction.ts b/app/database/operator/utils/reaction.ts index 92484e6158..7a42d4febe 100644 --- a/app/database/operator/utils/reaction.ts +++ b/app/database/operator/utils/reaction.ts @@ -3,8 +3,9 @@ import {Q} from '@nozbe/watermelondb'; import {MM_TABLES} from '@constants/database'; -import {RecordPair, SanitizeReactionsArgs} from '@typings/database/database'; -import Reaction from '@typings/database/models/servers/reaction'; + +import type {RecordPair, SanitizeReactionsArgs} from '@typings/database/database'; +import type ReactionModel from '@typings/database/models/servers/reaction'; const {REACTION} = MM_TABLES.SERVER; @@ -22,10 +23,10 @@ export const sanitizeReactions = async ({database, post_id, rawReactions}: Sanit const reactions = (await database.collections. get(REACTION). query(Q.where('post_id', post_id)). - fetch()) as Reaction[]; + fetch()) as ReactionModel[]; // similarObjects: Contains objects that are in both the RawReaction array and in the Reaction table - const similarObjects: Reaction[] = []; + const similarObjects: ReactionModel[] = []; const createReactions: RecordPair[] = []; diff --git a/app/database/operator/utils/test.ts b/app/database/operator/utils/test.ts index cfea868a31..b95456417c 100644 --- a/app/database/operator/utils/test.ts +++ b/app/database/operator/utils/test.ts @@ -4,15 +4,15 @@ import DatabaseManager from '@database/manager'; import {createPostsChain, sanitizePosts} from '@database/operator/utils/post'; import {sanitizeReactions} from '@database/operator/utils/reaction'; -import {RawPost} from '@typings/database/database'; -import Reaction from '@typings/database/models/servers/reaction'; + +import type ReactionModel from '@typings/database/models/servers/reaction'; import {mockedPosts, mockedReactions} from './mock'; describe('DataOperator: Utils tests', () => { it('=> sanitizePosts: should filter between ordered and unordered posts', () => { const {postsOrdered, postsUnordered} = sanitizePosts({ - posts: Object.values(mockedPosts.posts), + posts: Object.values(mockedPosts.posts) as Post[], orders: mockedPosts.order, }); expect(postsOrdered.length).toBe(4); @@ -23,42 +23,42 @@ describe('DataOperator: Utils tests', () => { const previousPostId = 'prev_xxyuoxmehne'; const chainedOfPosts = createPostsChain({ orders: mockedPosts.order, - rawPosts: Object.values(mockedPosts.posts), + rawPosts: Object.values(mockedPosts.posts) as Post[], previousPostId, }); // eslint-disable-next-line max-nested-callbacks const post1 = chainedOfPosts.find((post) => { - const p = post.raw as unknown as RawPost; + const p = post.raw as Post; return p.id === '8swgtrrdiff89jnsiwiip3y1eoe'; - })?.raw as unknown as RawPost; + })?.raw as Post; expect(post1).toBeTruthy(); expect(post1?.prev_post_id).toBe(previousPostId); // eslint-disable-next-line max-nested-callbacks const post2 = chainedOfPosts.find((post) => { - const p = post.raw as unknown as RawPost; + const p = post.raw as Post; return p.id === '8fcnk3p1jt8mmkaprgajoxz115a'; - })?.raw as unknown as RawPost; + })?.raw as Post; expect(post2).toBeTruthy(); expect(post2!.prev_post_id).toBe('8swgtrrdiff89jnsiwiip3y1eoe'); // eslint-disable-next-line max-nested-callbacks const post3 = chainedOfPosts.find((post) => { - const p = post.raw as unknown as RawPost; + const p = post.raw as Post; return p.id === '3y3w3a6gkbg73bnj3xund9o5ic'; - })?.raw as unknown as RawPost; + })?.raw as Post; expect(post3).toBeTruthy(); expect(post3?.prev_post_id).toBe('8fcnk3p1jt8mmkaprgajoxz115a'); // eslint-disable-next-line max-nested-callbacks const post4 = chainedOfPosts.find((post) => { - const p = post.raw as unknown as RawPost; + const p = post.raw as Post; return p.id === '4btbnmticjgw7ewd3qopmpiwqw'; - })?.raw as unknown as RawPost; + })?.raw as Post; expect(post4).toBeTruthy(); expect(post4!.prev_post_id).toBe('3y3w3a6gkbg73bnj3xund9o5ic'); @@ -82,12 +82,10 @@ describe('DataOperator: Utils tests', () => { post_id: '8ww8kb1dbpf59fu4d5xhu5nf5w', emoji_name: 'tada_will_be_removed', create_at: 1601558322701, - update_at: 1601558322701, - delete_at: 0, }, ], prepareRecordsOnly: true, - }) as Reaction[]; + }) as ReactionModel[]; // Jest in not using the same database instance amongst the Singletons; hence, we are creating the reaction record here // eslint-disable-next-line max-nested-callbacks diff --git a/app/database/schema/server/table_schemas/post_metadata.ts b/app/database/schema/server/table_schemas/post_metadata.ts index d316be9a52..785da7e654 100644 --- a/app/database/schema/server/table_schemas/post_metadata.ts +++ b/app/database/schema/server/table_schemas/post_metadata.ts @@ -12,6 +12,5 @@ export default tableSchema({ columns: [ {name: 'data', type: 'string'}, {name: 'post_id', type: 'string', isIndexed: true}, - {name: 'type', type: 'string'}, ], }); diff --git a/app/database/schema/server/test.ts b/app/database/schema/server/test.ts index 412598f4ee..2a0ab64816 100644 --- a/app/database/schema/server/test.ts +++ b/app/database/schema/server/test.ts @@ -208,12 +208,10 @@ describe('*** Test schema for SERVER database ***', () => { columns: { data: {name: 'data', type: 'string'}, post_id: {name: 'post_id', type: 'string', isIndexed: true}, - type: {name: 'type', type: 'string'}, }, columnArray: [ {name: 'data', type: 'string'}, {name: 'post_id', type: 'string', isIndexed: true}, - {name: 'type', type: 'string'}, ], }, [POST]: { diff --git a/app/helpers/api/preference.ts b/app/helpers/api/preference.ts new file mode 100644 index 0000000000..d9f0ee9e1e --- /dev/null +++ b/app/helpers/api/preference.ts @@ -0,0 +1,26 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +export function getPreferenceValue(preferences: PreferenceType[], category: string, name: string, defaultValue: unknown = '') { + const pref = preferences.find((p) => p.category === category && p.name === name); + + return pref?.value || defaultValue; +} + +export function getPreferenceAsBool(preferences: PreferenceType[], category: string, name: string, defaultValue = false) { + const value = getPreferenceValue(preferences, category, name, defaultValue); + if (typeof value === 'boolean') { + return defaultValue; + } + + return value !== 'false'; +} + +export function getPreferenceAsInt(preferences: PreferenceType[], category: string, name: string, defaultValue = 0) { + const value = getPreferenceValue(preferences, category, name, defaultValue); + if (value) { + return parseInt(value as string, 10); + } + + return defaultValue; +} diff --git a/app/helpers/api/team.ts b/app/helpers/api/team.ts new file mode 100644 index 0000000000..adb1ea847a --- /dev/null +++ b/app/helpers/api/team.ts @@ -0,0 +1,62 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import {DEFAULT_LOCALE} from '@i18n'; + +export const selectDefaultTeam = (teams: Team[], locale = DEFAULT_LOCALE, userTeamOrderPreference = '', primaryTeam = '') => { + let defaultTeam; + + if (!teams.length) { + return defaultTeam; + } + + if (primaryTeam) { + defaultTeam = teams.find((t) => t.name.toLowerCase() === primaryTeam.toLowerCase()); + } + + if (!defaultTeam) { + defaultTeam = sortTeamsByUserPreference(teams, locale, userTeamOrderPreference)[0]; + } + + return defaultTeam; +}; + +export const sortTeamsByUserPreference = (teams: Team[], locale: string, teamsOrder = '') => { + if (!teams.length) { + return []; + } + + const teamsOrderList = teamsOrder.split(',').filter((t) => t); + + if (!teamsOrderList.length) { + return [...teams].sort(sortTeamsWithLocale(locale)); + } + + const customSortedTeams = teams.filter((team) => { + if (team !== null) { + return teamsOrderList.includes(team.id); + } + return false; + }).sort((a, b) => { + return teamsOrderList.indexOf(a.id) - teamsOrderList.indexOf(b.id); + }); + + const otherTeams = teams.filter((team) => { + if (team !== null) { + return !teamsOrderList.includes(team.id); + } + return false; + }).sort(sortTeamsWithLocale(locale)); + + return [...customSortedTeams, ...otherTeams]; +}; + +export function sortTeamsWithLocale(locale: string): (a: Team, b: Team) => number { + return (a: Team, b: Team): number => { + if (a.display_name !== b.display_name) { + return a.display_name.toLowerCase().localeCompare(b.display_name.toLowerCase(), locale, {numeric: true}); + } + + return a.name.toLowerCase().localeCompare(b.name.toLowerCase(), locale, {numeric: true}); + }; +} diff --git a/app/init/global_event_handler.ts b/app/init/global_event_handler.ts index 2f5b5ce818..11a3a27bf8 100644 --- a/app/init/global_event_handler.ts +++ b/app/init/global_event_handler.ts @@ -5,7 +5,7 @@ import {Alert, DeviceEventEmitter, Linking, Platform} from 'react-native'; import CookieManager, {Cookie} from '@react-native-cookies/cookies'; import semver from 'semver'; -import {fetchConfigAndLicense} from '@actions/remote/general'; +import {fetchConfigAndLicense} from '@actions/remote/systems'; import LocalConfig from '@assets/config.json'; import {General, REDIRECT_URL_SCHEME, REDIRECT_URL_SCHEME_DEV} from '@constants'; import DatabaseManager from '@database/manager'; diff --git a/app/queries/servers/preference.ts b/app/queries/servers/preference.ts new file mode 100644 index 0000000000..2c058cc38b --- /dev/null +++ b/app/queries/servers/preference.ts @@ -0,0 +1,15 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import type ServerDataOperator from '@database/operator/server_data_operator'; + +export const prepareMyPreferences = (operator: ServerDataOperator, preferences: PreferenceType[]) => { + try { + return operator.handlePreferences({ + prepareRecordsOnly: true, + preferences, + }); + } catch { + return undefined; + } +}; diff --git a/app/queries/servers/system.ts b/app/queries/servers/system.ts index d66ffd5ea3..c6d3f2f829 100644 --- a/app/queries/servers/system.ts +++ b/app/queries/servers/system.ts @@ -4,13 +4,15 @@ import {Database} from '@nozbe/watermelondb'; import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@constants/database'; -import System from '@typings/database/models/servers/system'; + +import type ServerDataOperator from '@database/operator/server_data_operator'; +import type SystemModel from '@typings/database/models/servers/system'; const {SERVER: {SYSTEM}} = MM_TABLES; export const queryCurrentChannelId = async (serverDatabase: Database) => { try { - const currentChannelId = await serverDatabase.get(SYSTEM).find(SYSTEM_IDENTIFIERS.CURRENT_CHANNEL_ID) as System; + const currentChannelId = await serverDatabase.get(SYSTEM).find(SYSTEM_IDENTIFIERS.CURRENT_CHANNEL_ID) as SystemModel; return currentChannelId?.value || ''; } catch { return ''; @@ -19,7 +21,7 @@ export const queryCurrentChannelId = async (serverDatabase: Database) => { export const queryCurrentUserId = async (serverDatabase: Database) => { try { - const currentUserId = await serverDatabase.get(SYSTEM).find(SYSTEM_IDENTIFIERS.CURRENT_USER_ID) as System; + const currentUserId = await serverDatabase.get(SYSTEM).find(SYSTEM_IDENTIFIERS.CURRENT_USER_ID) as SystemModel; return currentUserId?.value || ''; } catch { return ''; @@ -27,7 +29,7 @@ export const queryCurrentUserId = async (serverDatabase: Database) => { }; export const queryCommonSystemValues = async (database: Database) => { - const systemRecords = (await database.collections.get(SYSTEM).query().fetch()) as System[]; + const systemRecords = (await database.collections.get(SYSTEM).query().fetch()) as SystemModel[]; let config = {}; let license = {}; let currentChannelId = ''; @@ -61,3 +63,37 @@ export const queryCommonSystemValues = async (database: Database) => { license, }; }; + +export const prepareCommonSystemValues = ( + operator: ServerDataOperator, config: ClientConfig, license: ClientLicense, + currentUserId: string, currentTeamId: string, currentChannelId: string) => { + try { + return operator.handleSystem({ + systems: [ + { + id: SYSTEM_IDENTIFIERS.CONFIG, + value: JSON.stringify(config), + }, + { + id: SYSTEM_IDENTIFIERS.LICENSE, + value: JSON.stringify(license), + }, + { + id: SYSTEM_IDENTIFIERS.CURRENT_USER_ID, + value: currentUserId, + }, + { + id: SYSTEM_IDENTIFIERS.CURRENT_TEAM_ID, + value: currentTeamId, + }, + { + id: SYSTEM_IDENTIFIERS.CURRENT_CHANNEL_ID, + value: currentChannelId, + }, + ], + prepareRecordsOnly: true, + }); + } catch { + return undefined; + } +}; diff --git a/app/queries/servers/team.ts b/app/queries/servers/team.ts new file mode 100644 index 0000000000..6be57d92e8 --- /dev/null +++ b/app/queries/servers/team.ts @@ -0,0 +1,23 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import type ServerDataOperator from '@database/operator/server_data_operator'; + +export const prepareMyTeams = (operator: ServerDataOperator, teams: Team[], memberships: TeamMembership[], unreads: TeamUnread[]) => { + try { + const teamRecords = operator.handleTeam({prepareRecordsOnly: true, teams}); + const teamMembershipRecords = operator.handleTeamMemberships({prepareRecordsOnly: true, teamMemberships: memberships}); + const myTeams: MyTeam[] = unreads.map((unread) => { + const matchingTeam = memberships.find((team) => team.team_id === unread.team_id); + return {team_id: unread.team_id, roles: matchingTeam?.roles ?? '', is_unread: unread.msg_count > 0, mentions_count: unread.mention_count}; + }); + const myTeamRecords = operator.handleMyTeam({ + prepareRecordsOnly: true, + myTeams, + }); + + return [teamRecords, teamMembershipRecords, myTeamRecords]; + } catch { + return undefined; + } +}; diff --git a/app/screens/channel/index.tsx b/app/screens/channel/index.tsx index b101771a22..5d022c22fb 100644 --- a/app/screens/channel/index.tsx +++ b/app/screens/channel/index.tsx @@ -13,7 +13,7 @@ import { import type {LaunchProps} from '@typings/launch'; -import {logout} from '@actions/remote/user'; +import {logout} from '@actions/remote/general'; import {useServerUrl} from '@context/server_url'; import {useTheme} from '@context/theme'; diff --git a/app/screens/mfa/index.tsx b/app/screens/mfa/index.tsx index 334ee99b85..27bfd6f2e5 100644 --- a/app/screens/mfa/index.tsx +++ b/app/screens/mfa/index.tsx @@ -19,16 +19,14 @@ import {SafeAreaView} from 'react-native-safe-area-context'; import ErrorText from '@components/error_text'; import FormattedText from '@components/formatted_text'; import {login} from '@actions/remote/user'; -import {Config} from '@typings/database/models/servers/config'; -import {License} from '@typings/database/models/servers/license'; import {t} from '@utils/i18n'; import {preventDoubleTap} from '@utils/tap'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; type MFAProps = { - config: Partial; + config: Partial; goToChannel: () => void; - license: Partial; + license: Partial; loginId: string; password: string; serverUrl: string; diff --git a/app/screens/server/index.tsx b/app/screens/server/index.tsx index 3e5427814f..6a8b51873b 100644 --- a/app/screens/server/index.tsx +++ b/app/screens/server/index.tsx @@ -12,7 +12,8 @@ import Button from 'react-native-button'; import {Navigation, NavigationFunctionComponent} from 'react-native-navigation'; import {SafeAreaView} from 'react-native-safe-area-context'; -import {doPing, fetchConfigAndLicense} from '@actions/remote/general'; +import {doPing} from '@actions/remote/general'; +import {fetchConfigAndLicense} from '@actions/remote/systems'; import LocalConfig from '@assets/config.json'; import AppVersion from '@components/app_version'; import ErrorText, {ClientErrorWithIntl} from '@components/error_text'; diff --git a/babel.config.js b/babel.config.js index 12c2f2f371..70c7f6e8c1 100644 --- a/babel.config.js +++ b/babel.config.js @@ -27,6 +27,7 @@ module.exports = { '@constants': './app/constants', '@context': './app/context', '@database': './app/database', + '@helpers': './app/helpers', '@i18n': './app/i18n', '@init': './app/init', '@notifications': './app/notifications', diff --git a/tsconfig.json b/tsconfig.json index 7c0c773d00..ecf4461bff 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -42,6 +42,7 @@ "@constants/*": ["app/constants/*"], "@context/*": ["app/context/*"], "@database/*": ["app/database/*"], + "@helpers/*": ["app/helpers/*"], "@i18n": ["app/i18n/index"], "@init/*": ["app/init/*"], "@notifications": ["app/notifications/index"], diff --git a/types/api/channels.d.ts b/types/api/channels.d.ts index 7909d3d975..5ea8c1ce18 100644 --- a/types/api/channels.d.ts +++ b/types/api/channels.d.ts @@ -28,12 +28,13 @@ type Channel = { total_msg_count: number; extra_update_at: number; creator_id: string; - scheme_id: string; + scheme_id: string|null; isCurrent?: boolean; teammate_id?: string; status?: string; fake?: boolean; - group_constrained: boolean; + group_constrained: boolean|null; + shared: boolean|null; }; type ChannelWithTeamData = Channel & { team_display_name: string; @@ -41,6 +42,7 @@ type ChannelWithTeamData = Channel & { team_update_at: number; } type ChannelMembership = { + id?: string; channel_id: string; user_id: string; roles: string; @@ -48,9 +50,10 @@ type ChannelMembership = { msg_count: number; mention_count: number; notify_props: Partial; + last_post_at?: number; last_update_at: number; - scheme_user: boolean; - scheme_admin: boolean; + scheme_user?: boolean; + scheme_admin?: boolean; post_root_id?: string; }; type ChannelUnread = { diff --git a/types/api/emojis.d.ts b/types/api/emojis.d.ts index 5ffa667a2d..5de460b3ca 100644 --- a/types/api/emojis.d.ts +++ b/types/api/emojis.d.ts @@ -3,11 +3,12 @@ type EmojiCategory = ( | 'recent' - | 'people' - | 'nature' - | 'foods' - | 'activity' - | 'places' + | 'smileys-emotion' + | 'people-body' + | 'animals-nature' + | 'food-drink' + | 'travel-places' + | 'activities' | 'objects' | 'symbols' | 'flags' @@ -21,7 +22,6 @@ type CustomEmoji = { delete_at: number; creator_id: string; name: string; - category: 'custom'; }; type SystemEmoji = { diff --git a/types/api/files.d.ts b/types/api/files.d.ts index 49c3b95470..7668a85740 100644 --- a/types/api/files.d.ts +++ b/types/api/files.d.ts @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. type FileInfo = { - id: string; + id?: string; user_id: string; post_id: string; create_at: number; @@ -10,12 +10,13 @@ type FileInfo = { delete_at: number; name: string; extension: string; + mini_preview?: string; size: number; mime_type: string; width: number; height: number; has_preview_image: boolean; - clientId: string; + clientId?: string; localPath?: string; uri?: string; loading?: boolean; diff --git a/types/api/groups.d.ts b/types/api/groups.d.ts index 4fb759c83a..4e1c13d954 100644 --- a/types/api/groups.d.ts +++ b/types/api/groups.d.ts @@ -18,7 +18,7 @@ type Group = { delete_at: number; has_syncables: boolean; member_count: number; - scheme_admin: boolean; + scheme_admin?: boolean; allow_reference: boolean; }; type GroupTeam = { @@ -27,7 +27,7 @@ type GroupTeam = { team_type: string; group_id: string; auto_add: boolean; - scheme_admin: boolean; + scheme_admin?: boolean; create_at: number; delete_at: number; update_at: number; @@ -41,10 +41,12 @@ type GroupChannel = { team_type: string; group_id: string; auto_add: boolean; - scheme_admin: boolean; + scheme_admin?: boolean; create_at: number; delete_at: number; update_at: number; + member_count: number; + timezone_count: number; }; type GroupSyncables = { teams: GroupTeam[]; diff --git a/types/api/posts.d.ts b/types/api/posts.d.ts index 1a5ceae3b0..71c997a944 100644 --- a/types/api/posts.d.ts +++ b/types/api/posts.d.ts @@ -1,20 +1,22 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -type PostType = 'system_add_remove' | - 'system_add_to_channel' | - 'system_add_to_team' | - 'system_channel_deleted' | - 'system_channel_restored' | - 'system_displayname_change' | - 'system_convert_channel' | - 'system_ephemeral' | - 'system_header_change' | - 'system_join_channel' | - 'system_join_leave' | - 'system_leave_channel' | - 'system_purpose_change' | - 'system_remove_from_channel'; +type PostType = + | '' + | 'system_add_remove' + | 'system_add_to_channel' + | 'system_add_to_team' + | 'system_channel_deleted' + | 'system_channel_restored' + | 'system_displayname_change' + | 'system_convert_channel' + | 'system_ephemeral' + | 'system_header_change' + | 'system_join_channel' + | 'system_join_leave' + | 'system_leave_channel' + | 'system_purpose_change' + | 'system_remove_from_channel'; type PostEmbedType = 'image' | 'message_attachment' | 'opengraph'; @@ -32,11 +34,11 @@ type PostImage = { }; type PostMetadata = { - embeds: PostEmbed[]; - emojis: CustomEmoji[]; - files: FileInfo[]; - images: Dictionary; - reactions: Reaction[]; + embeds?: PostEmbed[]; + emojis?: CustomEmoji[]; + files?: FileInfo[]; + images?: Dictionary; + reactions?: Reaction[]; }; type Post = { @@ -59,10 +61,13 @@ type Post = { reply_count: number; file_ids?: any[]; metadata: PostMetadata; + last_reply_at?: number; failed?: boolean; user_activity_posts?: Post[]; state?: 'DELETED'; ownPost?: boolean; + prev_post_id?: string; + participants: null|string[]; }; type PostWithFormatData = Post & { diff --git a/types/api/reactions.d.ts b/types/api/reactions.d.ts index 614b6ffd06..4326c52361 100644 --- a/types/api/reactions.d.ts +++ b/types/api/reactions.d.ts @@ -2,6 +2,7 @@ // See LICENSE.txt for license information. type Reaction = { + id?: string; user_id: string; post_id: string; emoji_name: string; diff --git a/types/api/roles.d.ts b/types/api/roles.d.ts index f862cc1371..f96a1dc395 100644 --- a/types/api/roles.d.ts +++ b/types/api/roles.d.ts @@ -6,12 +6,12 @@ type ChannelModerationRoles = 'members' | 'guests'; type Role = { id: string; name: string; - display_name: string; - description: string; - create_at: number; - update_at: number; - delete_at: number; + display_name?: string; + description?: string; + create_at?: number; + update_at?: number; + delete_at?: number; permissions: string[]; - scheme_managed: boolean; - built_in: boolean; + scheme_managed?: boolean; + built_in?: boolean; }; diff --git a/types/api/slash_command.d.ts b/types/api/slash_command.d.ts new file mode 100644 index 0000000000..36232c5b9b --- /dev/null +++ b/types/api/slash_command.d.ts @@ -0,0 +1,22 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +type SlashCommand = { + id: string; + auto_complete: boolean; + auto_complete_desc: string; + auto_complete_hint: string; + create_at: number; + creator_id: string; + delete_at: number; + description: string; + display_name: string; + icon_url: string; + method: string; + team_id: string; + token: string; + trigger: string; + update_at: number; + url: string; + username: string; +}; diff --git a/types/api/teams.d.ts b/types/api/teams.d.ts index 9e342dab8c..0db87b7f8e 100644 --- a/types/api/teams.d.ts +++ b/types/api/teams.d.ts @@ -2,6 +2,7 @@ // See LICENSE.txt for license information. type TeamMembership = { + id?: string; mention_count: number; msg_count: number; team_id: string; @@ -35,7 +36,8 @@ type Team = { invite_id: string; allow_open_invite: boolean; scheme_id: string; - group_constrained: boolean; + group_constrained: boolean|null; + last_team_icon_update: number; }; type TeamsState = { diff --git a/types/api/users.d.ts b/types/api/users.d.ts index 8a1566ffc5..39fd63b7af 100644 --- a/types/api/users.d.ts +++ b/types/api/users.d.ts @@ -24,10 +24,10 @@ type UserProfile = { update_at: number; delete_at: number; username: string; - auth_data: string; + auth_data?: string; auth_service: string; email: string; - email_verified: boolean; + email_verified?: boolean; nickname: string; first_name: string; last_name: string; @@ -35,8 +35,9 @@ type UserProfile = { roles: string; locale: string; notify_props: UserNotifyProps; - terms_of_service_id: string; - terms_of_service_create_at: number; + props?: UserProps; + terms_of_service_id?: string; + terms_of_service_create_at?: number; timezone?: UserTimezone; is_bot: boolean; last_picture_update: number; @@ -78,3 +79,7 @@ type UserStatus = { last_activity_at: number; active_channel?: string; }; + +type UserProps = { + [userPropsName: string]: any; +}; diff --git a/types/database/database.d.ts b/types/database/database.d.ts index 76810288c3..98445da014 100644 --- a/types/database/database.d.ts +++ b/types/database/database.d.ts @@ -69,41 +69,40 @@ export type CreateServerDatabaseArgs = { export type HandleReactionsArgs = { prepareRecordsOnly: boolean; - reactions: RawReaction[]; + reactions: Reaction[]; }; export type HandleFilesArgs = { - files: RawFile[]; + files: FileInfo[]; prepareRecordsOnly: boolean; }; export type HandlePostMetadataArgs = { - embeds?: Array<{ embed: RawEmbed[]; postId: string }>; - images?: Array<{ images: Dictionary; postId: string }>; + metadatas: Metadata[]; prepareRecordsOnly: boolean; }; export type HandlePostsArgs = { orders: string[]; previousPostId?: string; - values: RawPost[]; + values: Post[]; }; export type SanitizeReactionsArgs = { database: Database; post_id: string; - rawReactions: RawReaction[]; + rawReactions: Reaction[]; }; export type ChainPostsArgs = { orders: string[]; previousPostId: string; - rawPosts: RawPost[]; + rawPosts: Post[]; }; export type SanitizePostsArgs = { orders: string[]; - posts: RawPost[]; + posts: Post[]; }; export type IdenticalRecordArgs = { @@ -151,101 +150,99 @@ type PrepareOnly = { } export type HandleInfoArgs = PrepareOnly & { - info: RawInfo[]; -} -export type HandleServersArgs = PrepareOnly & { - servers: RawServers[]; + info: AppInfo[]; } + export type HandleGlobalArgs = PrepareOnly & { - global: RawGlobal[]; + global: IdValue[]; } export type HandleRoleArgs = PrepareOnly & { - roles: RawRole[]; + roles: Role[]; } export type HandleCustomEmojiArgs = PrepareOnly & { - emojis: RawCustomEmoji[]; + emojis: CustomEmoji[]; } export type HandleSystemArgs = PrepareOnly & { - systems: RawSystem[]; + systems: IdValue[]; } export type HandleTOSArgs = PrepareOnly & { - termOfService: RawTermsOfService[]; + termOfService: TermsOfService[]; } export type HandleMyChannelArgs = PrepareOnly & { - myChannels: RawMyChannel[]; + myChannels: ChannelMembership[]; }; export type HandleChannelInfoArgs = PrepareOnly &{ - channelInfos: RawChannelInfo[]; + channelInfos: ChannelInfo[]; }; export type HandleMyChannelSettingsArgs = PrepareOnly & { - settings: RawMyChannelSettings[]; + settings: ChannelMembership[]; }; export type HandleChannelArgs = PrepareOnly & { - channels: RawChannel[]; + channels: Channel[]; }; export type HandleMyTeamArgs = PrepareOnly & { - myTeams: RawMyTeam[]; + myTeams: MyTeam[]; }; export type HandleSlashCommandArgs = PrepareOnly & { - slashCommands: RawSlashCommand[]; + slashCommands: SlashCommand[]; }; export type HandleTeamSearchHistoryArgs = PrepareOnly &{ - teamSearchHistories: RawTeamSearchHistory[]; + teamSearchHistories: TeamSearchHistory[]; }; export type HandleTeamChannelHistoryArgs = PrepareOnly & { - teamChannelHistories: RawTeamChannelHistory[]; + teamChannelHistories: TeamChannelHistory[]; }; export type HandleTeamArgs = PrepareOnly & { - teams: RawTeam[]; + teams: Team[]; }; export type HandleGroupsInChannelArgs = PrepareOnly & { - groupsInChannels: RawGroupsInChannel[]; + groupsInChannels: GroupChannel[]; }; export type HandleGroupsInTeamArgs = PrepareOnly &{ - groupsInTeams: RawGroupsInTeam[]; + groupsInTeams: GroupTeam[]; }; export type HandleGroupArgs = PrepareOnly & { - groups: RawGroup[]; + groups: Group[]; }; export type HandleChannelMembershipArgs = PrepareOnly & { - channelMemberships: RawChannelMembership[]; + channelMemberships: ChannelMembership[]; }; export type HandleGroupMembershipArgs = PrepareOnly & { - groupMemberships: RawGroupMembership[]; + groupMemberships: GroupMembership[]; }; export type HandleTeamMembershipArgs = PrepareOnly & { - teamMemberships: RawTeamMembership[]; + teamMemberships: TeamMembership[]; }; export type HandlePreferencesArgs = PrepareOnly & { - preferences: RawPreference[]; + preferences: PreferenceType[]; }; export type HandleUsersArgs = PrepareOnly & { - users: RawUser[]; + users: UserProfile[]; }; export type HandleDraftArgs = PrepareOnly & { - drafts: RawDraft[]; + drafts: Draft[]; }; export type LoginArgs = { @@ -257,7 +254,7 @@ export type LoginArgs = { password: string; }; -export type LoadMeArgs = { user?: RawUser; deviceToken?: string }; +export type LoadMeArgs = { user?: UserProfile; deviceToken?: string }; export type ServerUrlChangedArgs = { configRecord: System; @@ -277,439 +274,3 @@ export type ProcessRecordResults = { updateRaws: RecordPair[]; deleteRaws: Model[]; } - -export type RawGlobal = { - id: string; - value: string; -}; - -export type RawInfo = { - build_number: string; - created_at: number; - version_number: string; -}; - -export type RawServers = { - db_path: string; - display_name: string; - mention_count: number; - unread_count: number; - url: string; - isSecured: boolean; - lastActiveAt: number; -}; - -export type RawChannelInfo = { - channel_id: string; - guest_count: number; - header: string; - member_count: number; - pinned_post_count: number; - purpose: string; -}; - -export type RawChannelMembership = { - id?: string; - channel_id: string; - user_id: string; - roles: string; - last_viewed_at: number; - msg_count: number; - mention_count: number; - notify_props: { - desktop: string; - email: string; - ignore_channel_mentions: string; - mark_unread: string; - push: string; - }; - last_update_at: number; - scheme_guest: boolean; - scheme_user: boolean; - scheme_admin: boolean; - explicit_roles: string; -}; - -export type ChannelType = 'D' | 'O' | 'G' | 'P'; - -export type RawChannel = { - create_at: number; - creator_id: string; - delete_at: number; - display_name: string; - extra_update_at: number; - group_constrained: boolean | null; - header: string; - id: string; - last_post_at: number; - name: string; - policy_id: string; - props: Record | null; - purpose: string; - scheme_id: string | null; - shared: boolean | null; - team_id: string; - total_msg_count: number; - total_msg_count_root: number; - type: ChannelType; - update_at: number; -}; - -export type RawCustomEmoji = { - id: string; - name: string; - create_at?: number; - update_at?: number; - delete_at?: number; - creator_id: string; -}; - -export type RawDraft = { - channel_id: string; - files?: FileInfo[]; - message?: string; - root_id: string; -}; - -export type RawFile = { - create_at: number; - delete_at: number; - extension: string; - has_preview_image?: boolean; - height: number; - id?: string; - localPath?: string; - mime_type?: string; - mini_preview?: string; // thumbnail - name: string; - post_id: string; - size: number; - update_at: number; - user_id: string; - width?: number; -}; - -export type RawGroupMembership = { - id?: string; - user_id: string; - group_id: string; -}; - -export type RawGroup = { - create_at: number; - delete_at: number; - description: string; - display_name: string; - has_syncables: boolean; - id: string; - name: string; - remote_id: string; - source: string; - update_at: number; -}; - -export type RawGroupsInChannel = { - auto_add: boolean; - channel_display_name: string; - channel_id: string; - channel_type: string; - create_at: number; - delete_at: number; - group_id: string; - team_display_name: string; - team_id: string; - team_type: string; - update_at: number; - member_count: number; - timezone_count: number; -}; - -export type RawGroupsInTeam = { - auto_add: boolean; - create_at: number; - delete_at: number; - group_id: string; - team_display_name: string; - team_id: string; - team_type: string; - update_at: number; -}; - -export type RawMyChannelSettings = { - notify_props: NotifyProps; - channel_id: string; -}; - -export type RawMyChannel = { - channel_id: string; - last_post_at: number; - last_viewed_at: number; - mentions_count: number; - message_count: number; - roles: string; -}; - -export type RawMyTeam = { - team_id: string; - roles: string; - is_unread: boolean; - mentions_count: number; -}; - -export type RawEmbed = { data: {}; type: string; url: string }; - -export type RawPostMetadata = { - data: any; - type: string; - postId: string; -}; - -export interface PostMetadataTypes { - embeds: PostEmbed; - images: Dictionary; -} - -export interface PostEmbed { - type: PostEmbedType; - url: string; - data: Record; -} - -export interface PostImage { - height: number; - width: number; - format?: string; - frame_count?: number; -} - -export interface PostImageMetadata extends PostImage { - url: string; -} - -export type PostMetadataData = Record | PostImageMetadata; - -export type PostMetadataType = 'images' | 'embeds'; - -// The RawPost describes the shape of the object received from a getPosts request -export type RawPost = { - channel_id: string; - create_at: number; - delete_at: number; - edit_at: number; - file_ids?: string[]; - filenames?: string[]; - hashtags: string; - id: string; - is_pinned?: boolean; - last_reply_at?: number; - message: string; - original_id: string; - parent_id: string; - participants?: null; - pending_post_id: string; - prev_post_id?: string; // taken from getPosts API call; outside of post object - props: object; - reply_count?: number; - root_id: string; - type: string; - update_at: number; - user_id: string; - metadata?: { - embeds?: RawEmbed[]; - emojis?: RawCustomEmoji[]; - files?: RawFile[]; - images?: Dictionary; - reactions?: RawReaction[]; - }; -}; - -export type RawPostsInChannel = { - channel_id: string; - earliest: number; - latest: number; -}; - -export type RawPostsInThread = { - earliest: number; - latest?: number; - post_id: string; -}; - -export type RawPreference = { - category: string; - name: string; - user_id: string; - value: string; -}; - -export type RawReaction = { - id?: string; - create_at: number; - delete_at: number; - emoji_name: string; - post_id: string; - update_at: number; - user_id: string; -}; - -export type RawRole = { - id: string; - name: string; - display_name?: string; - description?: string; - permissions: string[]; - scheme_managed?: boolean; -}; - -export type RawSlashCommand = { - id: string; - auto_complete: boolean; - auto_complete_desc: string; - auto_complete_hint: string; - create_at: number; - creator_id: string; - delete_at: number; - description: string; - display_name: string; - icon_url: string; - method: string; - team_id: string; - token: string; - trigger: string; - update_at: number; - url: string; - username: string; -}; - -export type RawSystem = { - id: string; - value: string; -}; - -export type RawTeamChannelHistory = { - team_id: string; - channel_ids: string[]; -}; - -export type RawTeamMembership = { - id?: string; - delete_at: number; - explicit_roles: string; - roles: string; - scheme_admin: boolean; - scheme_guest: boolean; - scheme_user: boolean; - team_id: string; - user_id: string; -}; - -export type RawTeamSearchHistory = { - created_at: number; - display_term: string; - term: string; - team_id: string; -}; - -export type RawTeam = { - id: string; - allow_open_invite: boolean; - allowed_domains: string; - company_name: string; - create_at: number; - delete_at: number; - description: string; - display_name: string; - email: string; - group_constrained: boolean | null; - invite_id: string; - last_team_icon_update: number; - name: string; - scheme_id: string; - type: string; - update_at: number; -}; - -export type RawTermsOfService = { - id: string; - accepted_at: number; - create_at: number; - user_id: string; - text: string; -}; - -export type RawUser = { - id: string; - auth_service: string; - create_at: number; - delete_at: number; - email: string; - email_verified: boolean; - failed_attempts?: number; - first_name: string; - is_bot: boolean; - last_name: string; - last_password_update: number; - last_picture_update: number; - locale: string; - mfa_active?: boolean; - nickname: string; - notify_props: { - channel: boolean; - desktop: string; - desktop_sound: boolean; - email: boolean; - first_name: boolean; - mention_keys: string; - push: string; - auto_responder_active: boolean; - auto_responder_message: string; - desktop_notification_sound: string; // Not in use by the mobile app - push_status: string; - comments: string; - }; - position?: string; - props: UserProps; - roles: string; - timezone: { - useAutomaticTimezone: string; - manualTimezone: string; - automaticTimezone: string; - }; - terms_of_service_create_at?: number; - terms_of_service_id?: string; - update_at: number; - username: string; -}; - -export type RawValue = - | RawInfo - | RawChannel - | RawChannelInfo - | RawChannelMembership - | RawCustomEmoji - | RawDraft - | RawFile - | RawGlobal - | RawGroup - | RawGroupMembership - | RawGroupsInChannel - | RawGroupsInTeam - | RawMyChannel - | RawMyChannelSettings - | RawMyTeam - | RawPost - | RawPostMetadata - | RawPostsInChannel - | RawPostsInThread - | RawPreference - | RawReaction - | RawRole - | RawServers - | RawSlashCommand - | RawSystem - | RawTeam - | RawTeamChannelHistory - | RawTeamMembership - | RawTeamSearchHistory - | RawTermsOfService - | RawUser; diff --git a/types/database/index.d.ts b/types/database/index.d.ts deleted file mode 100644 index 7b22a97c15..0000000000 --- a/types/database/index.d.ts +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -interface NotifyProps { - channel: boolean; - desktop: string; - desktop_sound: boolean; - email: boolean; - first_name: boolean; - mention_keys: string; - push: string; -} - -interface UserProps { - [userPropsName: string]: any; -} - -interface Timezone { - automaticTimezone: string; - manualTimezone: string; - useAutomaticTimezone: string; -} - -interface FileInfo { - id: string; - user_id: string; - post_id: string; - create_at: number; - update_at: number; - delete_at: number; - name: string; - extension: string; - size: number; - mime_type: string; - width: number; - height: number; - has_preview_image: boolean; - clientId: string; - localPath?: string; - uri?: string; - loading?: boolean; -} - -type PostEmbedType = 'image' | 'message_attachment' | 'opengraph'; - -type PostType = - | 'system_add_remove' - | 'system_add_to_channel' - | 'system_add_to_team' - | 'system_channel_deleted' - | 'system_channel_restored' - | 'system_displayname_change' - | 'system_convert_channel' - | 'system_ephemeral' - | 'system_header_change' - | 'system_join_channel' - | 'system_join_leave' - | 'system_leave_channel' - | 'system_purpose_change' - | 'system_remove_from_channel'; diff --git a/types/database/models/app/global.d.ts b/types/database/models/app/global.d.ts index 183ed69f43..19b63d3b9a 100644 --- a/types/database/models/app/global.d.ts +++ b/types/database/models/app/global.d.ts @@ -7,7 +7,7 @@ import {Model} from '@nozbe/watermelondb'; * The Global model will act as a dictionary of name-value pairs. The value field can be a JSON object or any other * data type. It will hold information that applies to the whole app ( e.g. sidebar settings for tablets) */ -export default class Global extends Model { +export default class GlobalModel extends Model { /** table (name) : global */ static table: string; diff --git a/types/database/models/app/info.d.ts b/types/database/models/app/info.d.ts index fd3694d582..261ca9a1ae 100644 --- a/types/database/models/app/info.d.ts +++ b/types/database/models/app/info.d.ts @@ -7,7 +7,7 @@ import {Model} from '@nozbe/watermelondb'; * The App model will hold information - such as the version number, build number and creation date - * for the Mattermost mobile app. */ -export default class Info extends Model { +export default class InfoModel extends Model { /** table (name) : app */ static table: string; diff --git a/types/database/models/app/servers.d.ts b/types/database/models/app/servers.d.ts index c0a31103a8..9f2cea0be7 100644 --- a/types/database/models/app/servers.d.ts +++ b/types/database/models/app/servers.d.ts @@ -7,7 +7,7 @@ import {Model} from '@nozbe/watermelondb'; * The Server model will help us to identify the various servers a user will log in; in the context of * multi-server support system. The db_path field will hold the App-Groups file-path */ -export default class Servers extends Model { +export default class ServersModel extends Model { /** table (name) : servers */ static table: string; diff --git a/types/database/models/servers/channel.d.ts b/types/database/models/servers/channel.d.ts index a97d856770..c309d178aa 100644 --- a/types/database/models/servers/channel.d.ts +++ b/types/database/models/servers/channel.d.ts @@ -4,21 +4,10 @@ import {Query, Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import ChannelInfo from './channel_info'; -import ChannelMembership from './channel_membership'; -import Draft from './draft'; -import GroupsInChannel from './groups_in_channel'; -import MyChannel from './my_channel'; -import MyChannelSettings from './my_channel_settings'; -import Post from './post'; -import PostsInChannel from './posts_in_channel'; -import Team from './team'; -import User from './user'; - /** * The Channel model represents a channel in the Mattermost app. */ -export default class Channel extends Model { +export default class ChannelModel extends Model { /** table (name) : Channel */ static table: string; @@ -53,32 +42,32 @@ export default class Channel extends Model { type: string; /** members : Users belonging to this channel */ - members: ChannelMembership[]; + members: ChannelMembershipModel[]; /** drafts : All drafts for this channel */ - drafts: Draft[]; + drafts: DraftModel[]; /** groupsInChannel : Every group contained in this channel */ - groupsInChannel: GroupsInChannel[]; + groupsInChannel: GroupsInChannelModel[]; /** posts : All posts made in the channel */ - posts: Post[]; + posts: PostModel[]; /** postsInChannel : a section of the posts for that channel bounded by a range */ - postsInChannel: PostsInChannel[]; + postsInChannel: PostsInChannelModel[]; /** team : The TEAM to which this CHANNEL belongs */ - team: Relation; + team: Relation; /** creator : The USER who created this CHANNEL*/ - creator: Relation; + creator: Relation; /** info : Query returning extra information about this channel from the CHANNEL_INFO table */ - info: Query; + info: Query; /** membership : Query returning the membership data for the current user if it belongs to this channel */ - membership: Query; + membership: Query; /** settings: User specific settings/preferences for this channel */ - settings: Query; + settings: Query; } diff --git a/types/database/models/servers/channel_info.d.ts b/types/database/models/servers/channel_info.d.ts index 8b163cffb7..7c954f22eb 100644 --- a/types/database/models/servers/channel_info.d.ts +++ b/types/database/models/servers/channel_info.d.ts @@ -4,14 +4,12 @@ import {Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Channel from './channel'; - /** * ChannelInfo is an extension of the information contained in the Channel table. * In a Separation of Concerns approach, ChannelInfo will provide additional information about a channel but on a more * specific level. */ -export default class ChannelInfo extends Model { +export default class ChannelInfoModel extends Model { /** table (name) : ChannelInfo */ static table: string; @@ -37,5 +35,5 @@ export default class ChannelInfo extends Model { purpose: string; /** channel : The lazy query property to the record from the CHANNEL table */ - channel: Relation; + channel: Relation; } diff --git a/types/database/models/servers/channel_membership.d.ts b/types/database/models/servers/channel_membership.d.ts index 7b9c139938..516e6395c2 100644 --- a/types/database/models/servers/channel_membership.d.ts +++ b/types/database/models/servers/channel_membership.d.ts @@ -4,14 +4,11 @@ import {Query, Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Channel from './channel'; -import User from './user'; - /** * The ChannelMembership model represents the 'association table' where many channels have users and many users are on * channels ( N:N relationship between model Users and model Channel) */ -export default class ChannelMembership extends Model { +export default class ChannelMembershipModel extends Model { /** table (name) : ChannelMembership */ static table: string; @@ -25,7 +22,7 @@ export default class ChannelMembership extends Model { userId: string; /** memberChannel : The related channel this member belongs to */ - memberChannel: Relation; + memberChannel: Relation; /** memberUser : The related member belonging to the channel */ memberUser: Relation; @@ -33,10 +30,10 @@ export default class ChannelMembership extends Model { /** * getAllChannelsForUser - Retrieves all the channels that the user is part of */ - getAllChannelsForUser: Query; + getAllChannelsForUser: Query; /** * getAllUsersInChannel - Retrieves all the users who are part of this channel */ - getAllUsersInChannel: Query; + getAllUsersInChannel: Query; } diff --git a/types/database/models/servers/config.ts b/types/database/models/servers/config.ts deleted file mode 100644 index 544a8cc87f..0000000000 --- a/types/database/models/servers/config.ts +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -export type Config = { - AboutLink: string; - AllowBannerDismissal: string; - AllowCustomThemes: string; - AllowedThemes: string; - AndroidAppDownloadLink: string; - AndroidLatestVersion: string; - AndroidMinVersion: string; - AppDownloadLink: string; - AsymmetricSigningPublicKey: string; - AvailableLocales: string; - BannerColor: string; - BannerText: string; - BannerTextColor: string; - BuildDate: string; - BuildEnterpriseReady: string; - BuildHash: string; - BuildHashEnterprise: string; - BuildNumber: string; - CloseUnusedDirectMessages: string; - CustomBrandText: string; - CustomDescriptionText: string; - CustomTermsOfServiceId: string; - CustomTermsOfServiceReAcceptancePeriod: string; - CustomUrlSchemes: string; - DataRetentionEnableFileDeletion: string; - DataRetentionEnableMessageDeletion: string; - DataRetentionFileRetentionDays: string; - DataRetentionMessageRetentionDays: string; - DefaultClientLocale: string; - DefaultTheme: string; - DesktopLatestVersion: string; - DesktopMinVersion: string; - DiagnosticId: string; - DiagnosticsEnabled: string; - EmailLoginButtonBorderColor: string; - EmailLoginButtonColor: string; - EmailLoginButtonTextColor: string; - EmailNotificationContentsType: string; - EnableBanner: string; - EnableBotAccountCreation: string; - EnableChannelViewedMessages: string; - EnableCluster: string; - EnableCommands: string; - EnableCompliance: string; - EnableConfirmNotificationsToChannel: string; - EnableCustomBrand: string; - EnableCustomEmoji: string; - EnableCustomTermsOfService: string; - EnableDeveloper: string; - EnableDiagnostics: string; - EnableEmailBatching: string; - EnableEmailInvitations: string; - EnableEmojiPicker: string; - EnableFileAttachments: string; - EnableGifPicker: string; - EnableGuestAccounts: string; - EnableIncomingWebhooks: string; - EnableLatex: string; - EnableLdap: string; - EnableLinkPreviews: string; - EnableMarketplace: string; - EnableMetrics: string; - EnableMobileFileDownload: string; - EnableMobileFileUpload: string; - EnableMultifactorAuthentication: string; - EnableOAuthServiceProvider: string; - EnableOpenServer: string; - EnableOutgoingWebhooks: string; - EnablePostIconOverride: string; - EnablePostUsernameOverride: string; - EnablePreviewFeatures: string; - EnablePreviewModeBanner: string; - EnablePublicLink: string; - EnableSaml: string; - EnableSignInWithEmail: string; - EnableSignInWithUsername: string; - EnableSignUpWithEmail: string; - EnableSignUpWithGitLab: string; - EnableSignUpWithGoogle: string; - EnableSignUpWithOffice365: string; - EnableSignUpWithOpenId: string; - EnableSVGs: string; - EnableTesting: string; - EnableThemeSelection: string; - EnableTutorial: string; - EnableUserAccessTokens: string; - EnableUserCreation: string; - EnableUserDeactivation: string; - EnableUserTypingMessages: string; - EnableXToLeaveChannelsFromLHS: string; - EnforceMultifactorAuthentication: string; - ExperimentalChannelOrganization: string; - ExperimentalChannelSidebarOrganization: string; - ExperimentalClientSideCertCheck: string; - ExperimentalClientSideCertEnable: string; - ExperimentalEnableAuthenticationTransfer: string; - ExperimentalEnableAutomaticReplies: string; - ExperimentalEnableClickToReply: string; - ExperimentalEnableDefaultChannelLeaveJoinMessages: string; - ExperimentalEnablePostMetadata: string; - ExperimentalGroupUnreadChannels: string; - ExperimentalHideTownSquareinLHS: string; - ExperimentalPrimaryTeam: string; - ExperimentalTimezone: string; - ExperimentalTownSquareIsReadOnly: string; - ExperimentalViewArchivedChannels: string; - GfycatApiKey: string; - GfycatApiSecret: string; - GoogleDeveloperKey: string; - GuestAccountsEnforceMultifactorAuthentication: string; - HasImageProxy: string; - HelpLink: string; - IosAppDownloadLink: string; - IosLatestVersion: string; - IosMinVersion: string; - LdapFirstNameAttributeSet: string; - LdapLastNameAttributeSet: string; - LdapLoginButtonBorderColor: string; - LdapLoginButtonColor: string; - LdapLoginButtonTextColor: string; - LdapLoginFieldName: string; - LdapNicknameAttributeSet: string; - LdapPositionAttributeSet: string; - LockTeammateNameDisplay: string; - MaxFileSize: string; - MaxNotificationsPerChannel: string; - MinimumHashtagLength: string; - OpenIdButtonColor: string; - OpenIdButtonText: string; - PasswordMinimumLength: string; - PasswordRequireLowercase: string; - PasswordRequireNumber: string; - PasswordRequireSymbol: string; - PasswordRequireUppercase: string; - PluginsEnabled: string; - PostEditTimeLimit: string; - PrivacyPolicyLink: string; - ReportAProblemLink: string; - RequireEmailVerification: string; - RestrictDirectMessage: string; - RunJobs: string; - SamlFirstNameAttributeSet: string; - SamlLastNameAttributeSet: string; - SamlLoginButtonBorderColor: string; - SamlLoginButtonColor: string; - SamlLoginButtonText: string; - SamlLoginButtonTextColor: string; - SamlNicknameAttributeSet: string; - SamlPositionAttributeSet: string; - SendEmailNotifications: string; - SendPushNotifications: string; - ShowEmailAddress: string; - ShowFullName: string; - SiteName: string; - SiteURL: string; - SQLDriverName: string; - SupportEmail: string; - TeammateNameDisplay: string; - TermsOfServiceLink: string; - TimeBetweenUserTypingUpdatesMilliseconds: string; - Version: string; - WebsocketPort: string; - WebsocketSecurePort: string; - WebsocketURL: string; - ExtendSessionLengthWithActivity: string; -}; diff --git a/types/database/models/servers/custom_emoji.d.ts b/types/database/models/servers/custom_emoji.d.ts index 2a3586141b..f67d51759c 100644 --- a/types/database/models/servers/custom_emoji.d.ts +++ b/types/database/models/servers/custom_emoji.d.ts @@ -4,7 +4,7 @@ import {Model} from '@nozbe/watermelondb'; /** The CustomEmoji model describes all the custom emojis used in the Mattermost app */ -export default class CustomEmoji extends Model { +export default class CustomEmojiModel extends Model { /** table (name) : CustomEmoji */ static table: string; diff --git a/types/database/models/servers/draft.d.ts b/types/database/models/servers/draft.d.ts index 91c3173f47..8a81a44610 100644 --- a/types/database/models/servers/draft.d.ts +++ b/types/database/models/servers/draft.d.ts @@ -6,7 +6,7 @@ import Model, {Associations} from '@nozbe/watermelondb/Model'; /** * The Draft model represents the draft state of messages in Direct/Group messages and in channels */ -export default class Draft extends Model { +export default class DraftModel extends Model { /** table (name) : Draft */ static table: string; diff --git a/types/database/models/servers/file.d.ts b/types/database/models/servers/file.d.ts index d9100f2b7c..15033d87f7 100644 --- a/types/database/models/servers/file.d.ts +++ b/types/database/models/servers/file.d.ts @@ -4,12 +4,10 @@ import {Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Post from './post'; - /** * The File model works in pair with the Post model. It hosts information about the files shared in a Post */ -export default class File extends Model { +export default class FileModel extends Model { /** table (name) : File */ static table: string; @@ -44,5 +42,5 @@ export default class File extends Model { width: number; /** post : The related Post record for this file */ - post: Relation; + post: Relation; } diff --git a/types/database/models/servers/group.d.ts b/types/database/models/servers/group.d.ts index 3954455a19..211722a318 100644 --- a/types/database/models/servers/group.d.ts +++ b/types/database/models/servers/group.d.ts @@ -3,16 +3,12 @@ import Model, {Associations} from '@nozbe/watermelondb/Model'; -import GroupMembership from './group_membership'; -import GroupsInChannel from './groups_in_channel'; -import GroupsInTeam from './groups_in_team'; - /** * The Group model unifies/assembles users, teams and channels based on a common ground. For example, a group can be * all users who are in the mobile team. If one needs to send that group a message, then s/he can mention the group's * name in the message. (e.g @mobile_team) */ -export default class Group extends Model { +export default class GroupModel extends Model { /** table (name) : Group */ static table: string; @@ -26,11 +22,11 @@ export default class Group extends Model { name: string; /** groupsInChannel : All the related children records from GroupsInChannel */ - groupsInChannel: GroupsInChannel[]; + groupsInChannel: GroupsInChannelModel[]; /** groupsInTeam : All the related children records from GroupsInTeam */ - groupsInTeam: GroupsInTeam[]; + groupsInTeam: GroupsInTeamModel[]; /** groupMemberships : All the related children records from GroupMembership */ - groupMemberships: GroupMembership[]; + groupMemberships: GroupMembershipModel[]; } diff --git a/types/database/models/servers/group_membership.d.ts b/types/database/models/servers/group_membership.d.ts index 3c4bfde62c..9ccb22ce42 100644 --- a/types/database/models/servers/group_membership.d.ts +++ b/types/database/models/servers/group_membership.d.ts @@ -4,14 +4,11 @@ import {Query, Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Group from './group'; -import User from './user'; - /** * The GroupMembership model represents the 'association table' where many groups have users and many users are in * groups (relationship type N:N) */ -export default class GroupMembership extends Model { +export default class GroupMembershipModel extends Model { /** table (name) : GroupMembership */ static table: string; @@ -21,18 +18,18 @@ export default class GroupMembership extends Model { userId: string; /** memberGroup : The related group this user belongs to */ - memberGroup: Relation; + memberGroup: Relation; /** memberUser : The related user in the group */ - memberUser: Relation; + memberUser: Relation; /** * getAllGroupsForUser : Retrieves all the groups that the user is part of */ - getAllGroupsForUser: Query; + getAllGroupsForUser: Query; /** * getAllUsersInGroup : Retrieves all the users who are part of this group */ - getAllUsersInGroup: Query; + getAllUsersInGroup: Query; } diff --git a/types/database/models/servers/groups_in_channel.d.ts b/types/database/models/servers/groups_in_channel.d.ts index 8341c8d87d..0ab8783fc0 100644 --- a/types/database/models/servers/groups_in_channel.d.ts +++ b/types/database/models/servers/groups_in_channel.d.ts @@ -4,13 +4,10 @@ import {Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Channel from './channel'; -import Group from './group'; - /** * The GroupsInChannel links the Channel model with the Group model */ -export default class GroupsInChannel extends Model { +export default class GroupsInChannelModel extends Model { /** table (name) : GroupsInChannel */ static table: string; @@ -30,8 +27,8 @@ export default class GroupsInChannel extends Model { timezoneCount: number; /** channel : The related record to the parent Channel model */ - channel: Relation; + channel: Relation; /** group : The related record to the parent Group model */ - group: Relation; + group: Relation; } diff --git a/types/database/models/servers/groups_in_team.d.ts b/types/database/models/servers/groups_in_team.d.ts index 95ac18bc53..81462bf22d 100644 --- a/types/database/models/servers/groups_in_team.d.ts +++ b/types/database/models/servers/groups_in_team.d.ts @@ -4,13 +4,10 @@ import {Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Group from './group'; -import Team from './team'; - /** * The GroupsInTeam links the Team model with the Group model */ -export default class GroupsInTeam extends Model { +export default class GroupsInTeamModel extends Model { /** table (name) : GroupsInTeam */ static table: string; @@ -30,8 +27,8 @@ export default class GroupsInTeam extends Model { timezoneCount: number; /** team : The related record to the parent Team model */ - team: Relation; + team: Relation; /** group : The related record to the parent Team model */ - group: Relation; + group: Relation; } diff --git a/types/database/models/servers/license.ts b/types/database/models/servers/license.ts deleted file mode 100644 index a3dfb20108..0000000000 --- a/types/database/models/servers/license.ts +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See LICENSE.txt for license information. - -export type License = { - Announcement: string; - Cloud: string; - Cluster: string; - Company: string; - Compliance: string; - CustomPermissionsSchemes: string; - CustomTermsOfService: string; - DataRetention: string; - Elasticsearch: string; - EmailNotificationContents: string; - GoogleOAuth: string; - GuestAccounts: string; - GuestAccountsPermissions: string; - IDLoadedPushNotifications: string; - IsLicensed: string; - LDAP: string; - LDAPGroups: string; - LockTeammateNameDisplay: string; - MFA: string; - MHPNS: string; - MessageExport: string; - Metrics: string; - Office365OAuth: string; - OpenId: string; - RemoteClusterService: string; - SAML: string; - SharedChannels: string; - Users: string; -} diff --git a/types/database/models/servers/my_channel.d.ts b/types/database/models/servers/my_channel.d.ts index 625fda1d3c..5a60e9bbf6 100644 --- a/types/database/models/servers/my_channel.d.ts +++ b/types/database/models/servers/my_channel.d.ts @@ -4,12 +4,10 @@ import {Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Channel from './channel'; - /** * MyChannel is an extension of the Channel model but it lists only the Channels the app's user belongs to */ -export default class MyChannel extends Model { +export default class MyChannelModel extends Model { /** table (name) : MyChannel */ static table: string; @@ -35,5 +33,5 @@ export default class MyChannel extends Model { roles: string; /** channel : The relation pointing to the CHANNEL table */ - channel: Relation; + channel: Relation; } diff --git a/types/database/models/servers/my_channel_settings.d.ts b/types/database/models/servers/my_channel_settings.d.ts index 61c3ceb251..ab3b83a812 100644 --- a/types/database/models/servers/my_channel_settings.d.ts +++ b/types/database/models/servers/my_channel_settings.d.ts @@ -4,13 +4,11 @@ import {Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Channel from './channel'; - /** * The MyChannelSettings model represents the specific user's configuration to * the channel this user belongs to. */ -export default class MyChannelSettings extends Model { +export default class MyChannelSettingsModel extends Model { /** table (name) : MyChannelSettings */ static table: string; @@ -21,8 +19,8 @@ export default class MyChannelSettings extends Model { channelId: string; /** notify_props : Configurations with regards to this channel */ - notifyProps: NotifyProps; + notifyProps: Partial; /** channel : The relation pointing to the CHANNEL table */ - channel: Relation; + channel: Relation; } diff --git a/types/database/models/servers/my_team.d.ts b/types/database/models/servers/my_team.d.ts index 6f5fcb5013..5e2ed3b85a 100644 --- a/types/database/models/servers/my_team.d.ts +++ b/types/database/models/servers/my_team.d.ts @@ -4,12 +4,10 @@ import {Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Team from './team'; - /** * MyTeam represents only the teams that the current user belongs to */ -export default class MyTeam extends Model { +export default class MyTeamModel extends Model { /** table (name) : MyTeam */ static table: string; @@ -29,5 +27,5 @@ export default class MyTeam extends Model { teamId: string; /** team : The relation to the TEAM table, that this user belongs to */ - team: Relation; + team: Relation; } diff --git a/types/database/models/servers/post.d.ts b/types/database/models/servers/post.d.ts index d0d0e1c210..8899e6b11e 100644 --- a/types/database/models/servers/post.d.ts +++ b/types/database/models/servers/post.d.ts @@ -4,18 +4,10 @@ import {Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Channel from './channel'; -import Draft from './draft'; -import File from './file'; -import PostInThread from './posts_in_thread'; -import PostMetadata from './post_metadata'; -import Reaction from './reaction'; -import User from './user'; - /** * The Post model is the building block of communication in the Mattermost app. */ -export default class Post extends Model { +export default class PostModel extends Model { /** table (name) : Post */ static table: string; @@ -65,23 +57,23 @@ export default class Post extends Model { props: object; /** drafts : Every drafts associated with this Post */ - drafts: Draft; + drafts: DraftModel; /** files: All the files associated with this Post */ - files: File[]; + files: FileModel[]; /** postsInThread: Every posts associated to a thread */ - postsInThread: PostInThread[]; + postsInThread: PostInThreadModel[]; /** metadata: All the extra data associated with this Post */ - metadata: PostMetadata[]; + metadata: PostMetadataModel[]; /** reactions: All the reactions associated with this Post */ - reactions: Reaction[]; + reactions: ReactionModel[]; /** author: The author of this Post */ - author: Relation; + author: Relation; /** channel: The channel which is presenting this Post */ - channel: Relation; + channel: Relation; } diff --git a/types/database/models/servers/post_metadata.d.ts b/types/database/models/servers/post_metadata.d.ts index 297bde744b..d8a2df014a 100644 --- a/types/database/models/servers/post_metadata.d.ts +++ b/types/database/models/servers/post_metadata.d.ts @@ -4,12 +4,10 @@ import {Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Post from './post'; - /** * PostMetadata provides additional information on a POST */ -export default class PostMetadata extends Model { +export default class PostMetadataModel extends Model { /** table (name) : PostMetadata */ static table: string; @@ -19,12 +17,9 @@ export default class PostMetadata extends Model { /** post_id : The foreign key of the parent POST model */ postId: string; - /** type : The type will work in tandem with the value present in the field 'data'. One 'type' for each kind of 'data' */ - type: string; - /** data : Different types of data ranging from arrays, emojis, files to images and reactions. */ - data: PostMetadataTypes; + data: PostMetadata; /** post: The record representing the POST parent. */ - post: Relation; + post: Relation; } diff --git a/types/database/models/servers/posts_in_channel.d.ts b/types/database/models/servers/posts_in_channel.d.ts index 2154207f3b..40efadea65 100644 --- a/types/database/models/servers/posts_in_channel.d.ts +++ b/types/database/models/servers/posts_in_channel.d.ts @@ -4,13 +4,11 @@ import {Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Channel from './channel'; - /** * PostsInChannel model helps us to combine adjacent posts together without leaving * gaps in between for an efficient user reading experience of posts. */ -export default class PostsInChannel extends Model { +export default class PostsInChannelModel extends Model { /** table (name) : PostsInChannel */ static table: string; @@ -27,5 +25,5 @@ export default class PostsInChannel extends Model { latest: number; /** channel : The parent record of the channel for those posts */ - channel: Relation; + channel: Relation; } diff --git a/types/database/models/servers/posts_in_thread.d.ts b/types/database/models/servers/posts_in_thread.d.ts index b4b24adca5..e46a8dd11a 100644 --- a/types/database/models/servers/posts_in_thread.d.ts +++ b/types/database/models/servers/posts_in_thread.d.ts @@ -4,13 +4,11 @@ import {Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Post from './post'; - /** * PostsInThread model helps us to combine adjacent threads together without leaving * gaps in between for an efficient user reading experience for threads. */ -export default class PostsInThread extends Model { +export default class PostsInThreadModel extends Model { /** table (name) : PostsInThread */ static table: string; @@ -27,5 +25,5 @@ export default class PostsInThread extends Model { postId: string; /** post : The related record to the parent Post model */ - post: Relation; + post: Relation; } diff --git a/types/database/models/servers/preference.d.ts b/types/database/models/servers/preference.d.ts index b087d9529b..272aff1911 100644 --- a/types/database/models/servers/preference.d.ts +++ b/types/database/models/servers/preference.d.ts @@ -4,13 +4,11 @@ import {Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import User from './user'; - /** * The Preference model hold information about the user's preference in the app. * This includes settings about the account, the themes, etc. */ -export default class Preference extends Model { +export default class PreferenceModel extends Model { /** table (name) : Preference */ static table: string; @@ -30,5 +28,5 @@ export default class Preference extends Model { value: string; /** user : The related record to the parent User model */ - user: Relation; + user: Relation; } diff --git a/types/database/models/servers/reaction.d.ts b/types/database/models/servers/reaction.d.ts index 227c85052d..7ebe176991 100644 --- a/types/database/models/servers/reaction.d.ts +++ b/types/database/models/servers/reaction.d.ts @@ -4,13 +4,10 @@ import {Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import User from './user'; -import Post from './post'; - /** * The Reaction Model is used to present the reactions a user had on a particular post */ -export default class Reaction extends Model { +export default class ReactionModel extends Model { /** table (name) : Reaction */ static table: string; @@ -30,8 +27,8 @@ export default class Reaction extends Model { userId: string; /** user : The related record to the User model */ - user: Relation; + user: Relation; /** post : The related record to the Post model */ - post: Relation; + post: Relation; } diff --git a/types/database/models/servers/role.d.ts b/types/database/models/servers/role.d.ts index 4b9f541ac3..fbe2846f4a 100644 --- a/types/database/models/servers/role.d.ts +++ b/types/database/models/servers/role.d.ts @@ -4,7 +4,7 @@ import {Model} from '@nozbe/watermelondb'; /** The Role model will describe the set of permissions for each role */ -export default class Role extends Model { +export default class RoleModel extends Model { /** table (name) : Role */ static table: string; diff --git a/types/database/models/servers/slash_command.d.ts b/types/database/models/servers/slash_command.d.ts index c6762717c3..e86551c136 100644 --- a/types/database/models/servers/slash_command.d.ts +++ b/types/database/models/servers/slash_command.d.ts @@ -4,12 +4,10 @@ import {Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Team from './team'; - /** * The SlashCommand model describes the commands of the various commands available in each team. */ -export default class SlashCommand extends Model { +export default class SlashCommandModel extends Model { /** table (name) : SlashCommand */ static table: string; @@ -44,5 +42,5 @@ export default class SlashCommand extends Model { updateAt!: number; /** team : The related parent TEAM record */ - team: Relation; + team: Relation; } diff --git a/types/database/models/servers/system.d.ts b/types/database/models/servers/system.d.ts index 7c86322b31..20c3b2bada 100644 --- a/types/database/models/servers/system.d.ts +++ b/types/database/models/servers/system.d.ts @@ -8,7 +8,7 @@ import {Model} from '@nozbe/watermelondb'; * will mostly hold configuration information about the client, the licences and some * custom data (e.g. recent emoji used) */ -export default class System extends Model { +export default class SystemModel extends Model { /** table (name) : System */ static table: string; diff --git a/types/database/models/servers/team.d.ts b/types/database/models/servers/team.d.ts index 8edc11a6cb..9f487263f9 100644 --- a/types/database/models/servers/team.d.ts +++ b/types/database/models/servers/team.d.ts @@ -4,18 +4,10 @@ import {Query} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Channel from './channel'; -import GroupsInTeam from './groups_in_team'; -import MyTeam from './my_team'; -import SlashCommand from './slash_command'; -import TeamChannelHistory from './team_channel_history'; -import TeamMembership from './team_membership'; -import TeamSearchHistory from './team_search_history'; - /** * A Team houses and enables communication to happen across channels and users. */ -export default class Team extends Model { +export default class TeamModel extends Model { /** table (name) : Team */ static table: string; @@ -50,23 +42,23 @@ export default class Team extends Model { allowedDomains: string; /** channels : All the channels associated with this team */ - channels: Channel[]; + channels: ChannelModel[]; /** groupsInTeam : All the groups associated with this team */ - groupsInTeam: GroupsInTeam[]; + groupsInTeam: GroupsInTeamModel[]; /** myTeam : Retrieves additional information about the team that this user is possibly part of. This query might yield no result if the user isn't part of a team. */ - myTeam: Query; + myTeam: Query; /** slashCommands : All the slash commands associated with this team */ - slashCommands: SlashCommand[]; + slashCommands: SlashCommandModel[]; /** teamChannelHistory : A history of the channels in this team that has been visited, ordered by the most recent and capped to the last 5 */ - teamChannelHistory: Query; + teamChannelHistory: Query; /** members : All the users associated with this team */ - members: TeamMembership[]; + members: TeamMembershipModel[]; /** teamSearchHistories : All the searches performed on this team */ - teamSearchHistories: TeamSearchHistory[]; + teamSearchHistories: TeamSearchHistoryModel[]; } diff --git a/types/database/models/servers/team_channel_history.d.ts b/types/database/models/servers/team_channel_history.d.ts index 61181689a1..fa08146ed5 100644 --- a/types/database/models/servers/team_channel_history.d.ts +++ b/types/database/models/servers/team_channel_history.d.ts @@ -4,13 +4,11 @@ import {Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Team from './team'; - /** * The TeamChannelHistory model helps keeping track of the last channel visited * by the user. */ -export default class TeamChannelHistory extends Model { +export default class TeamChannelHistoryModel extends Model { /** table (name) : TeamChannelHistory */ static table: string; @@ -24,5 +22,5 @@ export default class TeamChannelHistory extends Model { channelIds: string[]; /** team : The related record from the parent Team model */ - team: Relation; + team: Relation; } diff --git a/types/database/models/servers/team_membership.d.ts b/types/database/models/servers/team_membership.d.ts index 9afbb0f782..335d6d9911 100644 --- a/types/database/models/servers/team_membership.d.ts +++ b/types/database/models/servers/team_membership.d.ts @@ -4,14 +4,11 @@ import {Query, Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import User from './user'; -import Team from './team'; - /** * The TeamMembership model represents the 'association table' where many teams have users and many users are in * teams (relationship type N:N) */ -export default class TeamMembership extends Model { +export default class TeamMembershipModel extends Model { /** table (name) : TeamMembership */ static table: string; @@ -25,18 +22,18 @@ export default class TeamMembership extends Model { userId: string; /** memberUser: The related user in the team */ - memberUser: Relation; + memberUser: Relation; /** memberTeam : The related team of users */ - memberTeam: Relation; + memberTeam: Relation; /** * getAllTeamsForUser - Retrieves all the teams that the user is part of */ - getAllTeamsForUser: Query; + getAllTeamsForUser: Query; /** * getAllUsersInTeam - Retrieves all the users who are part of this team */ - getAllUsersInTeam: Query; + getAllUsersInTeam: Query; } diff --git a/types/database/models/servers/team_search_history.d.ts b/types/database/models/servers/team_search_history.d.ts index fb18590081..46cecbb3aa 100644 --- a/types/database/models/servers/team_search_history.d.ts +++ b/types/database/models/servers/team_search_history.d.ts @@ -4,13 +4,11 @@ import {Relation} from '@nozbe/watermelondb'; import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Team from './team'; - /** * The TeamSearchHistory model holds the term searched within a team. The searches are performed * at team level in the app. */ -export default class TeamSearchHistory extends Model { +export default class TeamSearchHistoryModel extends Model { /** table (name) : TeamSearchHistory */ static table: string; @@ -30,5 +28,5 @@ export default class TeamSearchHistory extends Model { term: string; /** team : The related record to the parent team model */ - team: Relation; + team: Relation; } diff --git a/types/database/models/servers/terms_of_service.d.ts b/types/database/models/servers/terms_of_service.d.ts index 78f2610aca..1e0c30f67a 100644 --- a/types/database/models/servers/terms_of_service.d.ts +++ b/types/database/models/servers/terms_of_service.d.ts @@ -6,7 +6,7 @@ import {Model} from '@nozbe/watermelondb'; /** * The model for Terms of Service */ -export default class TermsOfService extends Model { +export default class TermsOfServiceModel extends Model { /** table (name) : TermsOfService */ static table: string; diff --git a/types/database/models/servers/user.d.ts b/types/database/models/servers/user.d.ts index 3cb6e3d98e..d697753543 100644 --- a/types/database/models/servers/user.d.ts +++ b/types/database/models/servers/user.d.ts @@ -3,19 +3,11 @@ import Model, {Associations} from '@nozbe/watermelondb/Model'; -import Channel from './channel'; -import ChannelMembership from './channel_membership'; -import GroupMembership from './group_membership'; -import Post from './post'; -import Preference from './preference'; -import Reaction from './reaction'; -import TeamMembership from './team_membership'; - /** * The User model represents the 'USER' table and its relationship to other * shareholders in the app. */ -export default class User extends Model { +export default class UserModel extends Model { /** table (name) : User */ static table: string; @@ -68,34 +60,34 @@ export default class User extends Model { username: string; /** notify_props : Notification preferences/configurations */ - notifyProps: NotifyProps; + notifyProps: UserNotifyProps | null; /** props : Custom objects ( e.g. custom status) can be stored in there. Its type definition is known as * 'excess property check' in Typescript land. We keep using it till we build up the final shape of this object. */ - props: UserProps; + props: UserProps | null; /** timezone : The timezone for this user */ - timezone: Timezone; + timezone: UserTimezone | null; /** channelsCreated : All the channels that this user created */ - channelsCreated: Channel[]; + channelsCreated: ChannelModel[]; /** channels : All the channels that this user is part of */ - channels: ChannelMembership[]; + channels: ChannelMembershipModel[]; /** groups : All the groups that this user is part of */ - groups: GroupMembership[]; + groups: GroupMembershipModel[]; /** posts : All the posts that this user has written*/ - posts: Post[]; + posts: PostModel[]; /** preferences : All user preferences */ - preferences: Preference[]; + preferences: PreferenceModel[]; /** reactions : All the reactions to posts that this user had */ - reactions: Reaction[]; + reactions: ReactionModel[]; /** teams : All the team that this user is part of */ - teams: TeamMembership[]; + teams: TeamMembershipModel[]; } diff --git a/types/database/raw_values.d.ts b/types/database/raw_values.d.ts new file mode 100644 index 0000000000..59ade07d08 --- /dev/null +++ b/types/database/raw_values.d.ts @@ -0,0 +1,108 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +type AppInfo = { + build_number: string; + created_at: number; + version_number: string; +}; + +type ChannelInfo = { + channel_id: string; + guest_count: number; + header: string; + member_count: number; + pinned_post_count: number; + purpose: string; +}; + +type Draft = { + channel_id: string; + files?: FileInfo[]; + message?: string; + root_id: string; +}; + +type GroupMembership = { + id?: string; + user_id: string; + group_id: string; +}; + +type MyTeam = { + team_id: string; + roles: string; + is_unread: boolean; + mentions_count: number; +}; + +type PostsInChannel = { + channel_id: string; + earliest: number; + latest: number; +}; + +type PostsInThread = { + earliest: number; + latest?: number; + post_id: string; +}; + +type Metadata = { + data: PostMetadata; + post_id: string; +} + +type IdValue = { + id: string; + value: string; +}; + +type TeamChannelHistory = { + team_id: string; + channel_ids: string[]; +}; + +type TeamSearchHistory = { + created_at: number; + display_term: string; + term: string; + team_id: string; +}; + +type TermsOfService = { + id: string; + accepted_at: number; + create_at: number; + user_id: string; + text: string; +}; + +type RawValue = + | AppInfo + | Channel + | ChannelInfo + | ChannelMembership + | CustomEmoji + | Draft + | FileInfo + | Group + | GroupMembership + | GroupChannel + | GroupTeam + | IdValue + | Metadata + | MyTeam + | Post + | PostsInChannel + | PostsInThread + | PreferenceType + | Reaction + | Role + | SlashCommand + | Team + | TeamChannelHistory + | TeamMembership + | TeamSearchHistory + | TermsOfService + | UserProfile diff --git a/types/global/preferences.d.ts b/types/global/preferences.d.ts index bffd2aeb50..27a3863b84 100644 --- a/types/global/preferences.d.ts +++ b/types/global/preferences.d.ts @@ -5,7 +5,7 @@ interface PreferenceType { category: string; name: string; user_id: string; - value?: string; + value: string; } interface PreferencesType {