<commit_before>import React, { useState, useEffect } from 'react';
import { c } from 'ttag';

import { prepareContacts } from 'proton-shared/lib/contacts/encrypt';
import { hasCategories, reOrderByPref } from 'proton-shared/lib/contacts/properties';
import { addContacts } from 'proton-shared/lib/api/contacts';
import getPublicKeysEmailHelper from 'proton-shared/lib/api/helpers/getPublicKeysEmailHelper';
import { extractScheme } from 'proton-shared/lib/api/helpers/mailSettings';
import {
    sortPinnedKeys,
    sortApiKeys,
    getContactPublicKeyModel,
    getIsValidForSending,
} from 'proton-shared/lib/keys/publicKeys';
import { uniqueBy } from 'proton-shared/lib/helpers/array';
import { getKeyInfoFromProperties, toKeyProperty } from 'proton-shared/lib/contacts/keyProperties';
import { DecryptedKey, Api, ContactPublicKeyModel } from 'proton-shared/lib/interfaces';
import { ContactProperties, ContactProperty } from 'proton-shared/lib/interfaces/contacts/Contact';
import { AddContactsApiResponses } from 'proton-shared/lib/interfaces/contacts/Import';

import { VCARD_KEY_FIELDS, CATEGORIES } from 'proton-shared/lib/contacts/constants';
import { API_CODES, CONTACT_MIME_TYPES, MIME_TYPES, MIME_TYPES_MORE, PGP_SCHEMES } from 'proton-shared/lib/constants';
import { noop } from 'proton-shared/lib/helpers/function';

import ContactMIMETypeSelect from '../../../components/contacts/ContactMIMETypeSelect';
import ContactPgpSettings from '../ContactPgpSettings';
import { useApi, useEventManager, useNotifications, useLoading, useMailSettings } from '../../../hooks';
import {
    Alert,
    Label,
    Field,
    Row,
    Info,
    DialogModal,
    ContentModal,
    InnerModal,
    FooterModal,
    Button,
    PrimaryButton,
    LinkButton,
    Icon,
} from '../../../components';

const { PGP_INLINE } = PGP_SCHEMES;
const { INCLUDE, IGNORE } = CATEGORIES;

interface Props {
    userKeysList: DecryptedKey[];
    contactID: string;
    properties: ContactProperties;
    emailProperty: ContactProperty;
    onClose?: () => void;
}

const ContactEmailSettingsModal = ({
    userKeysList,
    contactID,
    properties,
    emailProperty,
    onClose = noop,
    ...rest
}: Props) => {
    const { value: emailAddressValue, group: emailGroup } = emailProperty;
    const emailAddress = emailAddressValue as string;

    const api = useApi();
    const { call } = useEventManager();
    const [model, setModel] = useState<ContactPublicKeyModel>({} as ContactPublicKeyModel);
    const [showPgpSettings, setShowPgpSettings] = useState(false);
    const [loading, withLoading] = useLoading();
    const { createNotification } = useNotifications();
    const [mailSettings, loadingMailSettings] = useMailSettings();

    const isLoading = loading || loadingMailSettings;
    const isMimeTypeFixed = model?.isPGPInternal ? false : model?.isPGPExternalWithWKDKeys ? true : !!model?.sign;
    const hasPGPInline = model && mailSettings ? extractScheme(model, mailSettings) === PGP_INLINE : false;

    /**
     * Initialize the key model for the modal
     * @returns {Promise}
     */
    const prepare = async (api: Api) => {
        const apiKeysConfig = await getPublicKeysEmailHelper(api, emailAddress, true);
        const pinnedKeysConfig = await getKeyInfoFromProperties(properties, emailGroup || '');
        const publicKeyModel = await getContactPublicKeyModel({
            emailAddress,
            apiKeysConfig,
            pinnedKeysConfig: { ...pinnedKeysConfig, isContact: true },
        });
        setModel(publicKeyModel);
    };

    /**
     * Collect keys from the model to save
     * @param {String} group attached to the current email address
     * @returns {Array} key properties to save in the vCard
     */
    const getKeysProperties = (group: string) => {
        const allKeys = model?.isPGPInternal
            ? [...model?.publicKeys.apiKeys]
            : [...model?.publicKeys.apiKeys, ...model?.publicKeys?.pinnedKeys];
        const trustedKeys = allKeys.filter((publicKey) => model?.trustedFingerprints.has(publicKey.getFingerprint()));
        const uniqueTrustedKeys = uniqueBy(trustedKeys, (publicKey) => publicKey.getFingerprint());
        return uniqueTrustedKeys.map((publicKey, index) => toKeyProperty({ publicKey, group, index }));
    };

    /**
     * Save relevant key properties in the vCard
     * @returns {Promise}
     */
    const handleSubmit = async () => {
        const otherProperties = properties.filter(({ field, group }) => {
            return !['email', ...VCARD_KEY_FIELDS].includes(field) || (group && group !== emailGroup);
        });

        const emailProperties = [emailProperty, ...getKeysProperties(emailGroup || '')];

        if (model?.mimeType) {
            emailProperties.push({ field: 'x-pm-mimetype', value: model?.mimeType, group: emailGroup });
        }
        if (model?.isPGPExternalWithoutWKDKeys && model?.encrypt !== undefined) {
            emailProperties.push({ field: 'x-pm-encrypt', value: `${model?.encrypt}`, group: emailGroup });
        }
        if (model?.isPGPExternalWithoutWKDKeys && model?.sign !== undefined) {
            emailProperties.push({ field: 'x-pm-sign', value: `${model?.sign}`, group: emailGroup });
        }
        if (model?.isPGPExternalWithoutWKDKeys && model?.scheme) {
            emailProperties.push({ field: 'x-pm-scheme', value: model?.scheme, group: emailGroup });
        }

        const allProperties = reOrderByPref(otherProperties.concat(emailProperties));
        const Contacts = await prepareContacts([allProperties], userKeysList[0]);<commit_msg>PGP scheme should editable for any external email<commit_after>import React, { useState, useEffect } from 'react';
import { c } from 'ttag';

import { prepareContacts } from 'proton-shared/lib/contacts/encrypt';
import { hasCategories, reOrderByPref } from 'proton-shared/lib/contacts/properties';
import { addContacts } from 'proton-shared/lib/api/contacts';
import getPublicKeysEmailHelper from 'proton-shared/lib/api/helpers/getPublicKeysEmailHelper';
import { extractScheme } from 'proton-shared/lib/api/helpers/mailSettings';
import {
    sortPinnedKeys,
    sortApiKeys,
    getContactPublicKeyModel,
    getIsValidForSending,
} from 'proton-shared/lib/keys/publicKeys';
import { uniqueBy } from 'proton-shared/lib/helpers/array';
import { getKeyInfoFromProperties, toKeyProperty } from 'proton-shared/lib/contacts/keyProperties';
import { DecryptedKey, Api, ContactPublicKeyModel } from 'proton-shared/lib/interfaces';
import { ContactProperties, ContactProperty } from 'proton-shared/lib/interfaces/contacts/Contact';
import { AddContactsApiResponses } from 'proton-shared/lib/interfaces/contacts/Import';

import { VCARD_KEY_FIELDS, CATEGORIES } from 'proton-shared/lib/contacts/constants';
import { API_CODES, CONTACT_MIME_TYPES, MIME_TYPES, MIME_TYPES_MORE, PGP_SCHEMES } from 'proton-shared/lib/constants';
import { noop } from 'proton-shared/lib/helpers/function';

import ContactMIMETypeSelect from '../../../components/contacts/ContactMIMETypeSelect';
import ContactPgpSettings from '../ContactPgpSettings';
import { useApi, useEventManager, useNotifications, useLoading, useMailSettings } from '../../../hooks';
import {
    Alert,
    Label,
    Field,
    Row,
    Info,
    DialogModal,
    ContentModal,
    InnerModal,
    FooterModal,
    Button,
    PrimaryButton,
    LinkButton,
    Icon,
} from '../../../components';

const { PGP_INLINE } = PGP_SCHEMES;
const { INCLUDE, IGNORE } = CATEGORIES;

interface Props {
    userKeysList: DecryptedKey[];
    contactID: string;
    properties: ContactProperties;
    emailProperty: ContactProperty;
    onClose?: () => void;
}

const ContactEmailSettingsModal = ({
    userKeysList,
    contactID,
    properties,
    emailProperty,
    onClose = noop,
    ...rest
}: Props) => {
    const { value: emailAddressValue, group: emailGroup } = emailProperty;
    const emailAddress = emailAddressValue as string;

    const api = useApi();
    const { call } = useEventManager();
    const [model, setModel] = useState<ContactPublicKeyModel>({} as ContactPublicKeyModel);
    const [showPgpSettings, setShowPgpSettings] = useState(false);
    const [loading, withLoading] = useLoading();
    const { createNotification } = useNotifications();
    const [mailSettings, loadingMailSettings] = useMailSettings();

    const isLoading = loading || loadingMailSettings;
    const isMimeTypeFixed = model?.isPGPInternal ? false : model?.isPGPExternalWithWKDKeys ? true : !!model?.sign;
    const hasPGPInline = model && mailSettings ? extractScheme(model, mailSettings) === PGP_INLINE : false;

    /**
     * Initialize the key model for the modal
     * @returns {Promise}
     */
    const prepare = async (api: Api) => {
        const apiKeysConfig = await getPublicKeysEmailHelper(api, emailAddress, true);
        const pinnedKeysConfig = await getKeyInfoFromProperties(properties, emailGroup || '');
        const publicKeyModel = await getContactPublicKeyModel({
            emailAddress,
            apiKeysConfig,
            pinnedKeysConfig: { ...pinnedKeysConfig, isContact: true },
        });
        setModel(publicKeyModel);
    };

    /**
     * Collect keys from the model to save
     * @param {String} group attached to the current email address
     * @returns {Array} key properties to save in the vCard
     */
    const getKeysProperties = (group: string) => {
        const allKeys = model?.isPGPInternal
            ? [...model?.publicKeys.apiKeys]
            : [...model?.publicKeys.apiKeys, ...model?.publicKeys?.pinnedKeys];
        const trustedKeys = allKeys.filter((publicKey) => model?.trustedFingerprints.has(publicKey.getFingerprint()));
        const uniqueTrustedKeys = uniqueBy(trustedKeys, (publicKey) => publicKey.getFingerprint());
        return uniqueTrustedKeys.map((publicKey, index) => toKeyProperty({ publicKey, group, index }));
    };

    /**
     * Save relevant key properties in the vCard
     * @returns {Promise}
     */
    const handleSubmit = async () => {
        const otherProperties = properties.filter(({ field, group }) => {
            return !['email', ...VCARD_KEY_FIELDS].includes(field) || (group && group !== emailGroup);
        });

        const emailProperties = [emailProperty, ...getKeysProperties(emailGroup || '')];

        if (model?.mimeType) {
            emailProperties.push({ field: 'x-pm-mimetype', value: model?.mimeType, group: emailGroup });
        }
        if (model?.isPGPExternalWithoutWKDKeys && model?.encrypt !== undefined) {
            emailProperties.push({ field: 'x-pm-encrypt', value: `${model?.encrypt}`, group: emailGroup });
        }
        if (model?.isPGPExternalWithoutWKDKeys && model?.sign !== undefined) {
            emailProperties.push({ field: 'x-pm-sign', value: `${model?.sign}`, group: emailGroup });
        }
        if (model?.isPGPExternal && model?.scheme) {
            emailProperties.push({ field: 'x-pm-scheme', value: model?.scheme, group: emailGroup });
        }

        const allProperties = reOrderByPref(otherProperties.concat(emailProperties));
        const Contacts = await prepareContacts([allProperties], userKeysList[0]);
{'fraction_non_alphanumeric': 0.1257346393588602, 'fraction_numerical': 0.00017809439002671417, 'mean_word_length': 3.5915780866721176, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4942714', 'n_tokens_mistral': 3225, 'n_tokens_neox': 3233, 'n_words': 726}