Skip to content

Commit

Permalink
Merge branch 'dev' for release 6.3.17
Browse files Browse the repository at this point in the history
  • Loading branch information
gnepud committed Apr 8, 2024
2 parents 91a1dc1 + 9306703 commit b05b295
Show file tree
Hide file tree
Showing 49 changed files with 331 additions and 122 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

## Next release

## v6.3.17 2024 Avril 8

- improvement: add loader for create/delete availability slot
- improvement: allow admin configure memeber's profile gender/birthday as required
- improvement: add sp certificate for saml provider
- Fix a bug: unable to update a space with a deleted machine
- Fix a bug: unable to get invoice payment details if the account code is same for card/transfer payment method
- Fix a bug: unable to show machine/training picture
- updates translations

## v6.3.16 2024 March 11

- Fix a bug: set settlement by cash by default for local payment mean
Expand Down
3 changes: 2 additions & 1 deletion app/controllers/api/auth_providers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ def provider_params
elsif params['auth_provider']['providable_type'] == SamlProvider.name
params.require(:auth_provider)
.permit(:id, :name, :providable_type,
providable_attributes: [:id, :sp_entity_id, :idp_sso_service_url, :profile_url, :idp_cert_fingerprint, :idp_cert, :idp_slo_service_url],
providable_attributes: %i[id sp_entity_id idp_sso_service_url profile_url idp_cert_fingerprint idp_cert
idp_slo_service_url authn_requests_signed want_assertions_signed sp_certificate sp_private_key],
auth_provider_mappings_attributes: [:id, :local_model, :local_field, :api_field, :api_endpoint, :api_data_type,
:_destroy, { transformation: [:type, :format, :true_value, :false_value,
{ mapping: %i[from to] }] }])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export const ProviderForm: React.FC<ProviderFormProps> = ({ action, provider, on
currentFormValues={output.providable_attributes as OpenIdConnectProvider}
formState={formState}
setValue={setValue} />}
{providableType === 'SamlProvider' && <SamlForm register={register} strategyName={strategyName} formState={formState} />}
{providableType === 'SamlProvider' && <SamlForm register={register} control={control} strategyName={strategyName} formState={formState} />}
{providableType && providableType !== 'DatabaseProvider' && <DataMappingForm register={register}
control={control}
formState={formState}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { FormInput } from '../form/form-input';
import { UseFormRegister, FormState } from 'react-hook-form';
import { FormSwitch } from '../form/form-switch';
import { UseFormRegister, FormState, Control } from 'react-hook-form';
import { FieldValues } from 'react-hook-form/dist/types/fields';
import { useTranslation } from 'react-i18next';
import { FabOutputCopy } from '../base/fab-output-copy';
import ValidationLib from '../../lib/validation';

interface SamlFormProps<TFieldValues> {
interface SamlFormProps<TFieldValues, TContext extends object> {
register: UseFormRegister<TFieldValues>,
control: Control<TFieldValues, TContext>,
formState: FormState<TFieldValues>,
strategyName?: string,
}

/**
* Partial form to fill the OAuth2 settings for a new/existing authentication provider.
*/
export const SamlForm = <TFieldValues extends FieldValues>({ register, strategyName, formState }: SamlFormProps<TFieldValues>) => {
export const SamlForm = <TFieldValues extends FieldValues, TContext extends object>({ register, strategyName, formState, control }: SamlFormProps<TFieldValues, TContext>) => {
const { t } = useTranslation('admin');

/**
Expand All @@ -39,7 +40,7 @@ export const SamlForm = <TFieldValues extends FieldValues>({ register, strategyN
placeholder="https://sso.example.net..."
label={t('app.admin.authentication.saml_form.idp_sso_service_url')}
tooltip={t('app.admin.authentication.saml_form.idp_sso_service_url_help')}
rules={{ required: true, pattern: ValidationLib.urlRegex }}
rules={{ required: true }}
formState={formState} />
<FormInput id="providable_attributes.idp_cert_fingerprint"
register={register}
Expand All @@ -56,14 +57,29 @@ export const SamlForm = <TFieldValues extends FieldValues>({ register, strategyN
placeholder="https://exemple.net/user..."
label={t('app.admin.authentication.saml_form.profile_edition_url')}
tooltip={t('app.admin.authentication.saml_form.profile_edition_url_help')}
rules={{ required: true, pattern: ValidationLib.urlRegex }}
rules={{ required: true }}
formState={formState} />
<FormInput id="providable_attributes.idp_slo_service_url"
register={register}
placeholder="https://sso.exemple.net..."
label={t('app.admin.authentication.saml_form.idp_slo_service_url')}
tooltip={t('app.admin.authentication.saml_form.idp_slo_service_url_help')}
rules={{ pattern: ValidationLib.urlRegex }}
formState={formState} />
<FormSwitch id="providable_attributes.authn_requests_signed" control={control}
formState={formState}
label={t('app.admin.authentication.saml_form.authn_requests_signed')} />
<FormSwitch id="providable_attributes.want_assertions_signed" control={control}
formState={formState}
label={t('app.admin.authentication.saml_form.want_assertions_signed')} />
<FormInput id="providable_attributes.sp_certificate"
register={register}
placeholder="-----BEGIN CERTIFICATE-----...-----END CERTIFICATE-----"
label={t('app.admin.authentication.saml_form.sp_certificate')}
formState={formState} />
<FormInput id="providable_attributes.sp_private_key"
register={register}
placeholder="-----BEGIN RSA PRIVATE KEY-----...-----END RSA PRIVATE KEY-----"
label={t('app.admin.authentication.saml_form.sp_private_key')}
formState={formState} />
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ const MachineCard: React.FC<MachineCardProps> = ({ user, machine, onShowMachine,
if (!machine.machine_image_attributes?.attachment_url) {
return <div className="machine-picture no-picture" />;
}
console.log(machine.machine_image_attributes.attachment_url);

return (
<div className="machine-picture" style={{ backgroundImage: `url(${machine.machine_image_attributes.attachment_url}), url('/default-image.png')` }} onClick={handleShowMachine} />
<div className="machine-picture" style={{ backgroundImage: `url("${machine.machine_image_attributes.attachment_url}"), url('/default-image.png')` }} onClick={handleShowMachine} />
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export const UserProfileForm: React.FC<UserProfileFormProps> = ({ action, size,
});
setValue('invoicing_profile_attributes.user_profile_custom_fields_attributes', userProfileCustomFields);
}).catch(error => onError(error));
SettingAPI.query(['phone_required', 'address_required', 'external_id'])
SettingAPI.query(['phone_required', 'address_required', 'external_id', 'gender_required', 'birthday_required'])
.then(settings => setFieldsSettings(settings))
.catch(error => onError(error));
}, []);
Expand Down Expand Up @@ -185,7 +185,7 @@ export const UserProfileForm: React.FC<UserProfileFormProps> = ({ action, size,
<div className="fields-group">
<div className="personnal-data">
<h4>{t('app.shared.user_profile_form.personal_data')}</h4>
<GenderInput register={register} disabled={isDisabled} required tooltip={t('app.shared.user_profile_form.used_for_statistics')} />
<GenderInput register={register} disabled={isDisabled} required={fieldsSettings.get('gender_required') === 'true'} tooltip={t('app.shared.user_profile_form.used_for_statistics')} />
<div className="names">
<FormInput id="profile_attributes.last_name"
register={register}
Expand All @@ -205,7 +205,7 @@ export const UserProfileForm: React.FC<UserProfileFormProps> = ({ action, size,
register={register}
label={t('app.shared.user_profile_form.date_of_birth')}
disabled={isDisabled}
rules={{ required: true }}
rules={{ required: fieldsSettings.get('birthday_required') === 'true' }}
formState={formState}
type="date"
nullable />
Expand Down
14 changes: 13 additions & 1 deletion app/frontend/src/javascript/controllers/admin/calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,8 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
// number of slots for this availability
$scope.slots_nb = slots;

$scope.saving = false;

/**
* Adds or removes the provided machine from the current slot
* @param machine {Object}
Expand Down Expand Up @@ -867,9 +869,14 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
if ($scope.isOnlySubscriptions && $scope.selectedPlans.length > 0) {
$scope.availability.plan_ids = $scope.selectedPlans.map(function (p) { return p.id; });
}
$scope.saving = true;
return Availability.save(
{ availability: $scope.availability },
function (availability) { $uibModalInstance.close(availability); }
function (availability) { $uibModalInstance.close(availability); },
function (error) {
console.error(error);
$scope.saving = false;
}
);
};

Expand Down Expand Up @@ -1158,15 +1165,19 @@ Application.Controllers.controller('DeleteRecurrentAvailabilityController', ['$s
// with recurrent slots: how many slots should we delete?
$scope.deleteMode = 'single';

$scope.deleting = false;

/**
* Confirmation callback
*/
$scope.ok = function () {
const { id, start_at, end_at } = availabilityPromise;
$scope.deleting = true;
// the admin has confirmed, delete the slot
Availability.delete(
{ id, mode: $scope.deleteMode },
function (res) {
$scope.deleting = false;
// delete success
if (res.deleted > 1) {
growl.success(_t(
Expand All @@ -1185,6 +1196,7 @@ Application.Controllers.controller('DeleteRecurrentAvailabilityController', ['$s
});
},
function (res) {
$scope.deleting = false;
// not everything was deleted
const { data } = res;
if (data.total > 1) {
Expand Down
24 changes: 24 additions & 0 deletions app/frontend/src/javascript/controllers/admin/members.js
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,12 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
// is the address required in _member_form?
$scope.addressRequired = (settingsPromise.address_required === 'true');

// is the gender number required in _member_form?
$scope.genderRequired = (settingsPromise.gender_required === 'true');

// is the birthday required in _member_form?
$scope.birthdayRequired = (settingsPromise.birthday_required === 'true');

// is user validation required
$scope.enableUserValidationRequired = (settingsPromise.user_validation_required === 'true');

Expand Down Expand Up @@ -1060,6 +1066,12 @@ Application.Controllers.controller('NewMemberController', ['$scope', '$state', '
// is the address required to sign-up?
$scope.addressRequired = (settingsPromise.address_required === 'true');

// is the gender number required in _member_form?
$scope.genderRequired = (settingsPromise.gender_required === 'true');

// is the birthday required in _member_form?
$scope.birthdayRequired = (settingsPromise.birthday_required === 'true');

// Default member's profile parameters
$scope.user = {
plan_interval: '',
Expand Down Expand Up @@ -1205,6 +1217,12 @@ Application.Controllers.controller('NewAdminController', ['$state', '$scope', 'A
// is the address required in _admin_form?
$scope.addressRequired = (settingsPromise.address_required === 'true');

// is the gender number required in _admin_form?
$scope.genderRequired = (settingsPromise.gender_required === 'true');

// is the birthday required in _admin_form?
$scope.birthdayRequired = (settingsPromise.birthday_required === 'true');

// all available groups
$scope.groups = groupsPromise;

Expand Down Expand Up @@ -1276,6 +1294,12 @@ Application.Controllers.controller('NewManagerController', ['$state', '$scope',
// is the address required in _admin_form?
$scope.addressRequired = (settingsPromise.address_required === 'true');

// is the gender number required in _admin_form?
$scope.genderRequired = (settingsPromise.gender_required === 'true');

// is the birthday required in _admin_form?
$scope.birthdayRequired = (settingsPromise.birthday_required === 'true');

// list of all groups
$scope.groups = groupsPromise.filter(function (g) { return !g.disabled; });

Expand Down
6 changes: 6 additions & 0 deletions app/frontend/src/javascript/controllers/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
// is the address required to sign-up?
$scope.addressRequired = (settingsPromise.address_required === 'true');

// is the gender required to sign-up?
$scope.genderRequired = (settingsPromise.gender_required === 'true');

// is the birthday required to sign-up?
$scope.birthdayRequired = (settingsPromise.birthday_required === 'true');

// reCaptcha v2 site key (or undefined)
$scope.recaptchaSiteKey = settingsPromise.recaptcha_site_key;

Expand Down
5 changes: 5 additions & 0 deletions app/frontend/src/javascript/controllers/events.js.erb
Original file line number Diff line number Diff line change
Expand Up @@ -1096,15 +1096,19 @@ Application.Controllers.controller('DeleteRecurrentEventController', ['$scope',
// with recurrent slots: how many slots should we delete?
$scope.deleteMode = 'single';

$scope.deleting = false;

/**
* Confirmation callback
*/
$scope.ok = function () {
$scope.deleting = true;
const { id, start_at, end_at } = eventPromise;
// the admin has confirmed, delete the slot
Event.delete(
{ id, mode: $scope.deleteMode },
function (res) {
$scope.deleting = false;
// delete success
if (res.deleted > 1) {
growl.success(_t(
Expand All @@ -1122,6 +1126,7 @@ Application.Controllers.controller('DeleteRecurrentEventController', ['$scope',
});
},
function (res) {
$scope.deleting = false;
// not everything was deleted
const { data } = res;
if (data.total > 1) {
Expand Down
2 changes: 1 addition & 1 deletion app/frontend/src/javascript/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default class ApiLib {
...object,
...attachmentAttributes.reduce((a, name) => { return { ...a, [name]: null }; }, {})
}
}, { dateWithTimezone: true });
}, { dateWithTimezone: true, allowEmptyArrays: true });
attachmentAttributes.forEach((attr) => {
data.delete(`${name}[${attr}]`);
if (Array.isArray(object[attr])) {
Expand Down
4 changes: 4 additions & 0 deletions app/frontend/src/javascript/models/authentication-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ export interface SamlProvider {
idp_cert: string,
profile_url: string,
idp_slo_service_url: string,
sp_certificate: string,
sp_private_key: string,
authn_requests_signed: boolean,
want_assertions_signed: boolean
}

export interface MappingFields {
Expand Down
4 changes: 3 additions & 1 deletion app/frontend/src/javascript/models/setting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,9 @@ export const accountSettings = [
'user_change_group',
'user_validation_required',
'user_validation_required_list',
'family_account'
'family_account',
'gender_required',
'birthday_required'
] as const;

export const analyticsSettings = [
Expand Down
Loading

0 comments on commit b05b295

Please sign in to comment.