Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 2s
130 lines
4.8 KiB
TypeScript
130 lines
4.8 KiB
TypeScript
import { isOAuthUser, type IMeApiUser, type IUser, type IUserEmail, type IUserCalendar } from '@rocket.chat/core-typings';
|
|
import semver from 'semver';
|
|
|
|
import { Info } from '../../../app/utils/rocketchat.info';
|
|
import { resolveUsersByIds } from '../../lib/statusVisibility/resolveUsers';
|
|
import { getURL } from '../../lib/utils/getURL';
|
|
import { getUserPreference } from '../../lib/utils/lib/getUserPreference';
|
|
import { settings } from '../../settings';
|
|
|
|
const isVerifiedEmail = (me: IUser): false | IUserEmail | undefined => {
|
|
if (!me || !Array.isArray(me.emails)) {
|
|
return false;
|
|
}
|
|
|
|
return me.emails.find((email) => email.verified);
|
|
};
|
|
|
|
const getPreferencesWithDefaults = async (me: IUser): Promise<Record<string, unknown>> => {
|
|
const defaultUserSettingPrefix = 'Accounts_Default_User_Preferences_';
|
|
const allDefaultUserSettings = settings.getByRegexp(new RegExp(`^${defaultUserSettingPrefix}.*$`));
|
|
|
|
const accumulator: Record<string, any> = {};
|
|
for (const [key] of allDefaultUserSettings) {
|
|
const settingWithoutPrefix = key.replace(defaultUserSettingPrefix, ' ').trim();
|
|
accumulator[settingWithoutPrefix] = await getUserPreference(me, settingWithoutPrefix);
|
|
}
|
|
|
|
return accumulator;
|
|
};
|
|
|
|
const filterOutdatedVersionUpdateBanners = (banners: NonNullable<IUser['banners']>): IUser['banners'] => {
|
|
return Object.fromEntries(
|
|
Object.entries(banners).filter(([id]) => {
|
|
if (!id.startsWith('versionUpdate-')) {
|
|
return true;
|
|
}
|
|
|
|
const version = id.replace('versionUpdate-', '').replace(/_/g, '.');
|
|
if (!semver.valid(version) || semver.lte(version, Info.version)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}),
|
|
);
|
|
};
|
|
|
|
/**
|
|
* Returns the user's calendar settings based on their email domain and the configured mapping.
|
|
* If the email is not provided or the domain is not found in the mapping,
|
|
* it returns the default Outlook calendar settings.
|
|
* @param email - The user's email object, which may contain the address and verification status.
|
|
* @returns The calendar settings for the user, including Outlook calendar settings if enabled.
|
|
*/
|
|
const getUserCalendar = (email: false | IUserEmail | undefined): IUserCalendar => {
|
|
const calendarSettings: IUserCalendar = {};
|
|
|
|
const outlook = {
|
|
Enabled: settings.get<boolean>('Outlook_Calendar_Enabled'),
|
|
Exchange_Url: settings.get<string>('Outlook_Calendar_Exchange_Url'),
|
|
Outlook_Url: settings.get<string>('Outlook_Calendar_Outlook_Url'),
|
|
};
|
|
|
|
const domain = email ? email.address.split('@').pop() : undefined;
|
|
const outlookCalendarUrlMapping = settings.get<string>('Outlook_Calendar_Url_Mapping');
|
|
|
|
if (domain && outlookCalendarUrlMapping && outlookCalendarUrlMapping.includes(domain)) {
|
|
try {
|
|
const mappingObject = JSON.parse(outlookCalendarUrlMapping);
|
|
const mappedSettings = mappingObject[domain];
|
|
if (mappedSettings) {
|
|
outlook.Enabled = mappedSettings.Enabled ?? outlook.Enabled;
|
|
outlook.Exchange_Url = mappedSettings.Exchange_Url ?? outlook.Exchange_Url;
|
|
outlook.Outlook_Url = mappedSettings.Outlook_Url ?? outlook.Outlook_Url;
|
|
}
|
|
} catch (error) {
|
|
console.error('Invalid Outlook Calendar URL Mapping JSON:', error);
|
|
}
|
|
}
|
|
|
|
if (outlook.Enabled) {
|
|
calendarSettings.outlook = outlook;
|
|
}
|
|
|
|
return calendarSettings;
|
|
};
|
|
|
|
export async function getUserInfo(me: IUser, pullPreferences = true): Promise<IMeApiUser> {
|
|
const verifiedEmail = isVerifiedEmail(me);
|
|
|
|
const { statusVisibilityDenied, ...savedPreferences } = me.settings?.preferences ?? {};
|
|
|
|
const preferences = pullPreferences
|
|
? {
|
|
...(await getPreferencesWithDefaults(me)),
|
|
...savedPreferences,
|
|
...(settings.get<boolean>('Accounts_StatusVisibility_Enabled') &&
|
|
statusVisibilityDenied?.length && {
|
|
statusVisibilityDenied: (await resolveUsersByIds(statusVisibilityDenied)).usernames,
|
|
}),
|
|
}
|
|
: undefined;
|
|
|
|
return {
|
|
...me,
|
|
...(me.banners && { banners: filterOutdatedVersionUpdateBanners(me.banners) }),
|
|
email: verifiedEmail ? verifiedEmail.address : undefined,
|
|
settings: {
|
|
profile: {},
|
|
...(preferences && { preferences }),
|
|
calendar: getUserCalendar(verifiedEmail),
|
|
},
|
|
avatarUrl: getURL(`/avatar/${me.username}`, { cdn: false, full: true }),
|
|
isOAuthUser: isOAuthUser(me),
|
|
...(me.services && {
|
|
services: {
|
|
...(me.services.github && { github: me.services.github as Record<string, unknown> }),
|
|
...(me.services.gitlab && { gitlab: me.services.gitlab as Record<string, unknown> }),
|
|
...(me.services.email2fa?.enabled && { email2fa: { enabled: me.services.email2fa.enabled } }),
|
|
...(me.services.totp?.enabled && { totp: { enabled: me.services.totp.enabled } }),
|
|
password: {
|
|
// The password hash shouldn't be leaked but the client may need to know if it exists.
|
|
exists: Boolean(me.services?.password?.bcrypt),
|
|
},
|
|
},
|
|
}),
|
|
// Cast needed: spread of full IUser produces a superset; runtime response schema validates the actual shape
|
|
} as IMeApiUser;
|
|
}
|