209 lines
6.7 KiB
TypeScript
209 lines
6.7 KiB
TypeScript
// (C) Copyright 2015 Moodle Pty Ltd.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import { Injectable, Type } from '@angular/core';
|
|
|
|
import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate';
|
|
import { CoreError } from '@classes/errors/error';
|
|
import { AuthEmailSignupProfileField } from '@features/login/services/login-helper';
|
|
import { makeSingleton } from '@singletons';
|
|
import { CoreUserProfileField } from './user';
|
|
|
|
/**
|
|
* Interface that all user profile field handlers must implement.
|
|
*/
|
|
export interface CoreUserProfileFieldHandler extends CoreDelegateHandler {
|
|
/**
|
|
* Type of the field the handler supports. E.g. 'checkbox'.
|
|
*/
|
|
type: string;
|
|
|
|
/**
|
|
* Return the Component to use to display the user profile field.
|
|
* It's recommended to return the class of the component, but you can also return an instance of the component.
|
|
*
|
|
* @return The component (or promise resolved with component) to use, undefined if not found.
|
|
*/
|
|
getComponent(): Type<unknown> | Promise<Type<unknown>>;
|
|
|
|
/**
|
|
* Get the data to send for the field based on the input data.
|
|
*
|
|
* @param field User field to get the data for.
|
|
* @param signup True if user is in signup page.
|
|
* @param registerAuth Register auth method. E.g. 'email'.
|
|
* @param formValues Form Values.
|
|
* @return Data to send for the field.
|
|
*/
|
|
getData?(
|
|
field: AuthEmailSignupProfileField | CoreUserProfileField,
|
|
signup: boolean,
|
|
registerAuth: string,
|
|
formValues: Record<string, unknown>,
|
|
): Promise<CoreUserProfileFieldHandlerData | undefined>;
|
|
}
|
|
|
|
export interface CoreUserProfileFieldHandlerData {
|
|
/**
|
|
* Name of the custom field.
|
|
*/
|
|
name: string;
|
|
|
|
/**
|
|
* The type of the custom field
|
|
*/
|
|
type: string;
|
|
|
|
/**
|
|
* Value of the custom field.
|
|
*/
|
|
value: unknown;
|
|
}
|
|
|
|
/**
|
|
* Service to interact with user profile fields.
|
|
*/
|
|
@Injectable({ providedIn: 'root' })
|
|
export class CoreUserProfileFieldDelegateService extends CoreDelegate<CoreUserProfileFieldHandler> {
|
|
|
|
protected handlerNameProperty = 'type';
|
|
|
|
constructor() {
|
|
super('CoreUserProfileFieldDelegate', true);
|
|
}
|
|
|
|
/**
|
|
* Get the type of a field.
|
|
*
|
|
* @param field The field to get its type.
|
|
* @return The field type.
|
|
*/
|
|
protected getType(field: AuthEmailSignupProfileField | CoreUserProfileField): string {
|
|
return ('type' in field ? field.type : field.datatype) || '';
|
|
}
|
|
|
|
/**
|
|
* Get the component to use to display an user field.
|
|
*
|
|
* @param field User field to get the directive for.
|
|
* @param signup True if user is in signup page.
|
|
* @return Promise resolved with component to use, undefined if not found.
|
|
*/
|
|
async getComponent(
|
|
field: AuthEmailSignupProfileField | CoreUserProfileField,
|
|
signup: boolean,
|
|
): Promise<Type<unknown> | undefined> {
|
|
const type = this.getType(field);
|
|
|
|
try {
|
|
if (signup) {
|
|
return await this.executeFunction(type, 'getComponent', []);
|
|
} else {
|
|
return await this.executeFunctionOnEnabled(type, 'getComponent', []);
|
|
}
|
|
} catch (error) {
|
|
this.logger.error('Error getting component for field', type, error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the data to send for a certain field based on the input data.
|
|
*
|
|
* @param field User field to get the data for.
|
|
* @param signup True if user is in signup page.
|
|
* @param registerAuth Register auth method. E.g. 'email'.
|
|
* @param formValues Form values.
|
|
* @return Data to send for the field.
|
|
*/
|
|
async getDataForField(
|
|
field: AuthEmailSignupProfileField | CoreUserProfileField,
|
|
signup: boolean,
|
|
registerAuth: string,
|
|
formValues: Record<string, unknown>,
|
|
): Promise<CoreUserProfileFieldHandlerData | undefined> {
|
|
const type = this.getType(field);
|
|
const handler = this.getHandler(type, !signup);
|
|
|
|
if (handler) {
|
|
const name = 'profile_field_' + field.shortname;
|
|
|
|
if (handler.getData) {
|
|
return await handler.getData(field, signup, registerAuth, formValues);
|
|
} else if (field.shortname && formValues[name] !== undefined) {
|
|
// Handler doesn't implement the function, but the form has data for the field.
|
|
return {
|
|
type: type,
|
|
name: name,
|
|
value: formValues[name],
|
|
};
|
|
}
|
|
}
|
|
|
|
throw new CoreError('User profile field handler not found.');
|
|
}
|
|
|
|
/**
|
|
* Get the data to send for a list of fields based on the input data.
|
|
*
|
|
* @param fields User fields to get the data for.
|
|
* @param signup True if user is in signup page.
|
|
* @param registerAuth Register auth method. E.g. 'email'.
|
|
* @param formValues Form values.
|
|
* @return Data to send.
|
|
*/
|
|
async getDataForFields(
|
|
fields: (AuthEmailSignupProfileField | CoreUserProfileField)[] | undefined,
|
|
signup: boolean = false,
|
|
registerAuth: string = '',
|
|
formValues: Record<string, unknown>,
|
|
): Promise<CoreUserProfileFieldHandlerData[]> {
|
|
if (!fields) {
|
|
return [];
|
|
}
|
|
|
|
const result: CoreUserProfileFieldHandlerData[] = [];
|
|
|
|
await Promise.all(fields.map(async (field) => {
|
|
try {
|
|
const data = await this.getDataForField(field, signup, registerAuth, formValues);
|
|
|
|
if (data) {
|
|
result.push(data);
|
|
}
|
|
} catch (error) {
|
|
// Ignore errors.
|
|
}
|
|
}));
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Check if any of the profile fields is not supported in the app.
|
|
*
|
|
* @param fields List of fields.
|
|
* @return Whether any of the profile fields is not supported in the app.
|
|
*/
|
|
hasRequiredUnsupportedField(fields?: AuthEmailSignupProfileField[]): boolean {
|
|
if (!fields || !fields.length) {
|
|
return false;
|
|
}
|
|
|
|
return fields.some((field) => field.required && !this.hasHandler(this.getType(field)));
|
|
}
|
|
|
|
}
|
|
|
|
export const CoreUserProfileFieldDelegate = makeSingleton(CoreUserProfileFieldDelegateService);
|