1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-11 05:54:15 +01:00

1240 lines
40 KiB
JavaScript
Raw Normal View History

/* eslint-disable
handle-callback-err,
no-return-assign,
no-self-assign,
no-undef,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS101: Remove unnecessary use of Array.from
* DS102: Remove unnecessary code created because of implicit returns
* DS207: Consider shorter variations of null checks
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
2018-11-21 11:08:53 +01:00
'use strict';
/* COMMON CODE */
2018-11-19 16:17:49 +01:00
/**
* Provides a set of common properties and methods to the $scope parameter. They are used
* in the various members' admin controllers.
*
* Provides :
* - $scope.groups = [{Group}]
* - $scope.trainings = [{Training}]
* - $scope.plans = []
* - $scope.datePicker = {}
* - $scope.submited(content)
* - $scope.cancel()
* - $scope.fileinputClass(v)
* - $scope.openDatePicker($event)
* - $scope.openSubscriptionDatePicker($event)
*
* Requires :
* - $state (Ui-Router) [ 'app.admin.members' ]
*/
class MembersController {
constructor ($scope, $state, Group, Training) {
// Retrieve the profiles groups (e.g. students ...)
2018-11-21 11:08:53 +01:00
Group.query(function (groups) { $scope.groups = groups.filter(function (g) { return (g.slug !== 'admins') && !g.disabled; }); });
2018-11-19 16:17:49 +01:00
// Retrieve the list of available trainings
2018-11-20 12:26:06 +01:00
Training.query().$promise.then(function (data) {
$scope.trainings = data.map(function (d) {
return ({
id: d.id,
name: d.name,
disabled: d.disabled
2018-11-21 11:08:53 +01:00
});
});
});
2018-11-19 16:17:49 +01:00
// Default parameters for AngularUI-Bootstrap datepicker
$scope.datePicker = {
format: Fablab.uibDateFormat,
opened: false, // default: datePicker is not shown
subscription_date_opened: false,
options: {
2016-03-23 18:39:41 +01:00
startingDay: Fablab.weekStartingDay
}
2018-11-21 11:08:53 +01:00
};
2018-11-19 16:17:49 +01:00
/**
* Shows the birthday datepicker
2018-11-19 16:17:49 +01:00
* @param $event {Object} jQuery event object
*/
$scope.openDatePicker = function ($event) {
2018-11-21 11:08:53 +01:00
$event.preventDefault();
$event.stopPropagation();
return $scope.datePicker.opened = true;
};
2018-11-19 16:17:49 +01:00
/**
* Shows the end of subscription datepicker
* @param $event {Object} jQuery event object
*/
$scope.openSubscriptionDatePicker = function ($event) {
2018-11-21 11:08:53 +01:00
$event.preventDefault();
$event.stopPropagation();
return $scope.datePicker.subscription_date_opened = true;
};
2018-11-19 16:17:49 +01:00
/**
* For use with ngUpload (https://github.com/twilson63/ngUpload).
* Intended to be the callback when an upload is done: any raised error will be stacked in the
* $scope.alerts array. If everything goes fine, the user is redirected to the members listing page.
* @param content {Object} JSON - The result of the upload
2018-11-19 16:17:49 +01:00
*/
$scope.submited = function (content) {
if ((content.id == null)) {
2018-11-21 11:08:53 +01:00
$scope.alerts = [];
2018-11-20 12:26:06 +01:00
return angular.forEach(content, function (v, k) {
angular.forEach(v, function (err) {
$scope.alerts.push({
msg: k + ': ' + err,
2016-03-23 18:39:41 +01:00
type: 'danger'
2018-11-21 11:08:53 +01:00
});
});
});
} else {
2018-11-21 11:08:53 +01:00
return $state.go('app.admin.members');
}
2018-11-21 11:08:53 +01:00
};
2016-03-23 18:39:41 +01:00
2018-11-19 16:17:49 +01:00
/**
* Changes the admin's view to the members list page
*/
2018-11-21 11:08:53 +01:00
$scope.cancel = function () { $state.go('app.admin.members'); };
2016-03-23 18:39:41 +01:00
2018-11-19 16:17:49 +01:00
/**
* For use with 'ng-class', returns the CSS class name for the uploads previews.
* The preview may show a placeholder, or the content of the file depending on the upload state.
2018-11-19 16:17:49 +01:00
* @param v {*} any attribute, will be tested for truthiness (see JS evaluation rules)
*/
$scope.fileinputClass = function (v) {
if (v) {
2018-11-21 11:08:53 +01:00
return 'fileinput-exists';
} else {
2018-11-21 11:08:53 +01:00
return 'fileinput-new';
}
2018-11-21 11:08:53 +01:00
};
}
}
2016-03-23 18:39:41 +01:00
2018-11-19 16:17:49 +01:00
/**
* Controller used in the members/groups management page
*/
Application.Controllers.controller('AdminMembersController', ['$scope', '$sce', '$uibModal', 'membersPromise', 'adminsPromise', 'partnersPromise', 'managersPromise', 'growl', 'Admin', 'AuthService', 'dialogs', '_t', 'Member', 'Export', 'User', 'uiTourService', 'settingsPromise', '$location',
function ($scope, $sce, $uibModal, membersPromise, adminsPromise, partnersPromise, managersPromise, growl, Admin, AuthService, dialogs, _t, Member, Export, User, uiTourService, settingsPromise, $location) {
/* PRIVATE STATIC CONSTANTS */
2016-05-30 15:39:19 +02:00
// number of users loaded each time we click on 'load more...'
2018-11-21 11:08:53 +01:00
const USERS_PER_PAGE = 20;
2016-03-23 18:39:41 +01:00
/* PUBLIC SCOPE */
2018-11-19 16:17:49 +01:00
// members list
2018-11-21 11:08:53 +01:00
$scope.members = membersPromise;
$scope.member = {
2018-11-19 16:17:49 +01:00
// Members plain-text filtering. Default: not filtered
searchText: '',
2018-11-19 16:17:49 +01:00
// Members ordering/sorting. Default: not sorted
order: 'id',
// the currently displayed page of members
page: 1,
2018-11-19 16:17:49 +01:00
// true when all members where loaded
noMore: false,
// default filter for members
memberFilter: 'all',
// options for members filtering
memberFilters: [
'all',
'not_confirmed',
'inactive_for_3_years'
]
2018-11-21 11:08:53 +01:00
};
2018-11-19 16:17:49 +01:00
// admins list
$scope.admins = adminsPromise.admins.filter(function (m) { return m.id !== Fablab.adminSysId; });
// is user validation required
$scope.enableUserValidationRequired = (settingsPromise.user_validation_required === 'true');
// should we display the username in the list?
$scope.displayUsername = (settingsPromise.show_username_in_admin_list === 'true');
2018-11-19 16:17:49 +01:00
// Admins ordering/sorting. Default: not sorted
2018-11-21 11:08:53 +01:00
$scope.orderAdmin = null;
2020-04-21 16:47:35 +02:00
// partners list
$scope.partners = partnersPromise.users;
// Partners ordering/sorting. Default: not sorted
$scope.orderPartner = null;
// managers list
$scope.managers = managersPromise.users;
// Managers ordering/sorting. Default: not sorted
$scope.orderManager = null;
2020-02-19 13:00:38 +01:00
// default tab: members list
const defaultActiveTab = $location.search().tabs ? parseInt($location.search().tabs, 10) : 0;
$scope.tabs = { active: defaultActiveTab, sub: 0 };
2020-02-19 13:00:38 +01:00
2018-11-19 16:17:49 +01:00
/**
* Change the members ordering criterion to the one provided
* @param orderBy {string} ordering criterion
*/
$scope.setOrderMember = function (orderBy) {
if ($scope.member.order === orderBy) {
2018-11-21 11:08:53 +01:00
$scope.member.order = `-${orderBy}`;
} else {
2018-11-21 11:08:53 +01:00
$scope.member.order = orderBy;
}
2018-11-21 11:08:53 +01:00
resetSearchMember();
return memberSearch();
};
2018-11-19 16:17:49 +01:00
/**
* Change the admins ordering criterion to the one provided
2018-11-20 12:26:06 +01:00
* @param orderAdmin {string} ordering criterion
2018-11-19 16:17:49 +01:00
*/
$scope.setOrderAdmin = function (orderAdmin) {
if ($scope.orderAdmin === orderAdmin) {
2018-11-21 11:08:53 +01:00
return $scope.orderAdmin = `-${orderAdmin}`;
} else {
2018-11-21 11:08:53 +01:00
return $scope.orderAdmin = orderAdmin;
}
2018-11-21 11:08:53 +01:00
};
2020-04-21 16:47:35 +02:00
/**
* Change the partners ordering criterion to the one provided
* @param orderPartner {string} ordering criterion
*/
$scope.setOrderPartner = function (orderPartner) {
if ($scope.orderPartner === orderPartner) {
2020-04-21 16:47:35 +02:00
return $scope.orderPartner = `-${orderPartner}`;
} else {
return $scope.orderPartner = orderPartner;
}
};
2020-04-21 17:24:22 +02:00
/**
* Change the managers ordering criterion to the one provided
* @param orderManager {string} ordering criterion
*/
$scope.setOrderManager = function (orderManager) {
if ($scope.orderManager === orderManager) {
return $scope.orderManager = `-${orderManager}`;
} else {
return $scope.orderManager = orderManager;
}
};
2020-04-21 16:47:35 +02:00
/**
* Open a modal dialog allowing the admin to create a new partner user
*/
$scope.openPartnerNewModal = function () {
const modalInstance = $uibModal.open({
animation: true,
templateUrl: '/shared/_partner_new_modal.html',
2020-04-21 16:47:35 +02:00
size: 'lg',
controller: ['$scope', '$uibModalInstance', 'User', function ($scope, $uibModalInstance, User) {
$scope.partner = {};
$scope.ok = function () {
User.save(
{},
{ user: $scope.partner },
function (user) {
$scope.partner.id = user.id;
$scope.partner.name = `${user.first_name} ${user.last_name}`;
$uibModalInstance.close($scope.partner);
},
function (error) {
growl.error(_t('app.admin.plans.new.unable_to_save_this_user_check_that_there_isnt_an_already_a_user_with_the_same_name'));
console.error(error);
}
);
};
$scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };
}]
});
// once the form was validated successfully ...
return modalInstance.result.then(function (partner) {
$scope.partners.push(partner);
});
};
2019-10-29 09:59:21 +01:00
/**
* Ask for confirmation then delete the specified user
* @param memberId {number} identifier of the user to delete
*/
$scope.deleteMember = function (memberId) {
2019-10-29 09:59:21 +01:00
dialogs.confirm(
{
resolve: {
object () {
return {
title: _t('app.admin.members.confirmation_required'),
msg: $sce.trustAsHtml(_t('app.admin.members.confirm_delete_member') + '<br/><br/>' + _t('app.admin.members.this_may_take_a_while_please_wait'))
2019-10-29 09:59:21 +01:00
};
}
}
},
function () { // cancel confirmed
Member.delete(
{ id: memberId },
function () {
$scope.members.splice(findItemIdxById($scope.members, memberId), 1);
return growl.success(_t('app.admin.members.member_successfully_deleted'));
2019-10-29 09:59:21 +01:00
},
function (error) {
growl.error(_t('app.admin.members.unable_to_delete_the_member'));
console.error(error);
}
2019-10-29 09:59:21 +01:00
);
}
);
};
2019-10-29 09:59:21 +01:00
2018-11-19 16:17:49 +01:00
/**
* Ask for confirmation then delete the specified administrator
* @param admins {Array} full list of administrators
* @param admin {Object} administrator to delete
*/
2018-11-20 12:26:06 +01:00
$scope.destroyAdmin = function (admins, admin) {
dialogs.confirm(
{
resolve: {
object () {
return {
title: _t('app.admin.members.confirmation_required'),
msg: $sce.trustAsHtml(_t('app.admin.members.do_you_really_want_to_delete_this_administrator_this_cannot_be_undone') + '<br/><br/>' + _t('app.admin.members.this_may_take_a_while_please_wait'))
2018-11-21 11:08:53 +01:00
};
}
}
2018-11-20 12:26:06 +01:00
},
function () { // cancel confirmed
Admin.delete(
{ id: admin.id },
function () {
2019-10-29 09:59:21 +01:00
admins.splice(findItemIdxById(admins, admin.id), 1);
return growl.success(_t('app.admin.members.administrator_successfully_deleted'));
2018-11-20 12:26:06 +01:00
},
function (error) {
growl.error(_t('app.admin.members.unable_to_delete_the_administrator'));
console.error(error);
}
2018-11-21 11:08:53 +01:00
);
}
2018-11-21 11:08:53 +01:00
);
};
2020-04-21 16:47:35 +02:00
/**
* Ask for confirmation then delete the specified partner
* @param partners {Array} full list of partners
* @param partner {Object} partner to delete
*/
$scope.destroyPartner = function (partners, partner) {
dialogs.confirm(
{
resolve: {
object () {
return {
title: _t('app.admin.members.confirmation_required'),
msg: $sce.trustAsHtml(_t('app.admin.members.delete_this_partner') + '<br/><br/>' + _t('app.admin.members.this_may_take_a_while_please_wait'))
};
}
}
},
function () { // cancel confirmed
User.delete(
{ id: partner.id },
function () {
partners.splice(findItemIdxById(partners, partner.id), 1);
return growl.success(_t('app.admin.members.partner_successfully_deleted'));
},
function (error) {
growl.error(_t('app.admin.members.unable_to_delete_the_partner'));
console.error(error);
}
2020-04-21 16:47:35 +02:00
);
}
);
};
2020-04-21 16:47:35 +02:00
2020-04-21 17:24:22 +02:00
/**
* Ask for confirmation then delete the specified manager
* @param managers {Array} full list of managers
* @param manager {Object} manager to delete
*/
$scope.destroyManager = function (managers, manager) {
dialogs.confirm(
{
resolve: {
object () {
return {
title: _t('app.admin.members.confirmation_required'),
msg: $sce.trustAsHtml(_t('app.admin.members.delete_this_manager') + '<br/><br/>' + _t('app.admin.members.this_may_take_a_while_please_wait'))
};
}
}
},
function () { // cancel confirmed
User.delete(
{ id: manager.id },
function () {
managers.splice(findItemIdxById(managers, manager.id), 1);
return growl.success(_t('app.admin.members.manager_successfully_deleted'));
},
function (error) {
growl.error(_t('app.admin.members.unable_to_delete_the_manager'));
console.error(error);
}
2020-04-21 17:24:22 +02:00
);
}
);
};
2020-04-21 17:24:22 +02:00
2018-11-19 16:17:49 +01:00
/**
* Callback for the 'load more' button.
* Will load the next results of the current search, if any
*/
$scope.showNextMembers = function () {
2018-11-21 11:08:53 +01:00
$scope.member.page += 1;
return memberSearch(true);
};
2018-11-19 16:17:49 +01:00
/**
* Callback when the search field content changes: reload the search results
*/
$scope.updateTextSearch = function () {
if (searchTimeout) clearTimeout(searchTimeout);
searchTimeout = setTimeout(function () {
resetSearchMember();
memberSearch();
}, 300);
2018-11-21 11:08:53 +01:00
};
/**
* Callback when the member filter changes: reload the search results
*/
$scope.updateMemberFilter = function () {
resetSearchMember();
memberSearch();
};
2018-11-19 16:17:49 +01:00
/**
* Callback to alert the admin that the export request was acknowledged and is
* processing right now.
*/
2018-11-20 12:26:06 +01:00
$scope.alertExport = function (type) {
Export.status({ category: 'users', type }).then(function (res) {
if (!res.data.exists) {
return growl.success(_t('app.admin.members.export_is_running_you_ll_be_notified_when_its_ready'));
}
2018-11-21 11:08:53 +01:00
});
};
2020-02-19 13:00:38 +01:00
/**
* Set up the feature-tour for the admin/members page.
2020-02-19 13:00:38 +01:00
* This is intended as a contextual help (when pressing F1)
*/
$scope.setupMembersTour = function () {
// get the tour defined by the ui-tour directive
const uitour = uiTourService.getTourByName('members');
uitour.createStep({
selector: 'body',
stepId: 'welcome',
order: 0,
title: _t('app.admin.tour.members.welcome.title'),
content: _t('app.admin.tour.members.welcome.content'),
placement: 'bottom',
orphan: true
});
uitour.createStep({
selector: '.members-management .members-list',
stepId: 'list',
order: 1,
title: _t('app.admin.tour.members.list.title'),
content: _t('app.admin.tour.members.list.content'),
placement: 'top'
});
uitour.createStep({
selector: '.members-management .search-members',
stepId: 'search',
order: 2,
title: _t('app.admin.tour.members.search.title'),
content: _t('app.admin.tour.members.search.content'),
placement: 'bottom'
});
uitour.createStep({
selector: '.members-management .filter-members',
stepId: 'filter',
order: 3,
title: _t('app.admin.tour.members.filter.title'),
content: _t('app.admin.tour.members.filter.content'),
placement: 'bottom'
});
2020-02-26 16:49:29 +01:00
if ($scope.members.length > 0) {
uitour.createStep({
selector: '.members-management .members-list .buttons',
stepId: 'actions',
order: 4,
title: _t('app.admin.tour.members.actions.title'),
content: _t('app.admin.tour.members.actions.content'),
placement: 'left'
});
}
2020-04-29 15:20:39 +02:00
if (AuthService.isAuthorized('admin')) {
uitour.createStep({
selector: '.members-management .exports-buttons',
stepId: 'exports',
order: 5,
title: _t('app.admin.tour.members.exports.title'),
content: _t('app.admin.tour.members.exports.content'),
placement: 'bottom'
});
uitour.createStep({
selector: '.heading .import-members',
stepId: 'import',
order: 6,
title: _t('app.admin.tour.members.import.title'),
content: _t('app.admin.tour.members.import.content'),
placement: 'left'
});
}
2020-02-19 14:30:56 +01:00
uitour.createStep({
selector: '.members-management .admins-tab',
stepId: 'admins',
2020-02-19 14:39:45 +01:00
order: 7,
2020-02-19 14:30:56 +01:00
title: _t('app.admin.tour.members.admins.title'),
content: _t('app.admin.tour.members.admins.content'),
placement: 'bottom'
});
2020-04-29 15:20:39 +02:00
if (AuthService.isAuthorized('admin')) {
uitour.createStep({
selector: '.members-management .groups-tab',
stepId: 'groups',
order: 8,
title: _t('app.admin.tour.members.groups.title'),
content: _t('app.admin.tour.members.groups.content'),
placement: 'bottom'
});
uitour.createStep({
selector: '.members-management .labels-tab',
stepId: 'labels',
order: 9,
title: _t('app.admin.tour.members.labels.title'),
content: _t('app.admin.tour.members.labels.content'),
placement: 'bottom'
});
uitour.createStep({
selector: '.members-management .sso-tab',
stepId: 'sso',
order: 10,
title: _t('app.admin.tour.members.sso.title'),
content: _t('app.admin.tour.members.sso.content'),
placement: 'bottom',
popupClass: 'shift-left-50'
});
}
2020-02-19 13:00:38 +01:00
uitour.createStep({
selector: 'body',
stepId: 'conclusion',
2020-02-19 14:39:45 +01:00
order: 11,
2020-02-19 13:00:38 +01:00
title: _t('app.admin.tour.conclusion.title'),
content: _t('app.admin.tour.conclusion.content'),
placement: 'bottom',
orphan: true
});
// on step change, change the active tab if needed
uitour.on('stepChanged', function (nextStep) {
2020-02-19 14:30:56 +01:00
if (nextStep.stepId === 'list' || nextStep.stepId === 'import') {
2020-02-19 13:00:38 +01:00
$scope.tabs.active = 0;
2020-04-21 16:47:35 +02:00
$scope.tabs.sub = 0;
2020-02-19 13:00:38 +01:00
}
2020-02-19 14:30:56 +01:00
if (nextStep.stepId === 'admins') {
2020-04-21 16:47:35 +02:00
$scope.tabs.active = 0;
$scope.tabs.sub = 1;
2020-02-19 14:30:56 +01:00
}
if (nextStep.stepId === 'groups') {
2020-04-21 16:47:35 +02:00
$scope.tabs.active = 1;
2020-02-19 14:30:56 +01:00
}
if (nextStep.stepId === 'labels') {
2020-04-21 16:47:35 +02:00
$scope.tabs.active = 2;
2020-02-19 14:30:56 +01:00
}
if (nextStep.stepId === 'sso') {
2020-04-21 16:47:35 +02:00
$scope.tabs.active = 3;
2020-02-19 14:30:56 +01:00
}
2020-02-19 13:00:38 +01:00
});
// on tour end, save the status in database
uitour.on('ended', function () {
if (uitour.getStatus() === uitour.Status.ON && $scope.currentUser.profile_attributes.tours.indexOf('members') < 0) {
2020-02-19 13:00:38 +01:00
Member.completeTour({ id: $scope.currentUser.id }, { tour: 'members' }, function (res) {
$scope.currentUser.profile_attributes.tours = res.tours;
2020-02-19 13:00:38 +01:00
});
}
});
// if the user has never seen the tour, show him now
if (settingsPromise.feature_tour_display !== 'manual' && $scope.currentUser.profile_attributes.tours.indexOf('members') < 0) {
2020-02-19 13:00:38 +01:00
uitour.start();
}
};
2020-02-19 13:00:38 +01:00
/* PRIVATE SCOPE */
2018-11-19 16:17:49 +01:00
/**
* Kind of constructor: these actions will be realized first when the controller is loaded
*/
const initialize = function () {
if (!membersPromise[0] || (membersPromise[0].maxMembers <= $scope.members.length)) {
2018-11-21 11:08:53 +01:00
return $scope.member.noMore = true;
}
2018-11-21 11:08:53 +01:00
};
/**
* Will temporize the search query to prevent overloading the API
*/
let searchTimeout = null;
2018-11-19 16:17:49 +01:00
/**
2019-10-29 09:59:21 +01:00
* Iterate through the provided array and return the index of the requested item
* @param items {Array} full list of users with the 'admin' role
2019-10-29 09:59:21 +01:00
* @param id {Number} id of the item to retrieve in the list
* @returns {Number} index of the requested item, in the provided array
2018-11-19 16:17:49 +01:00
*/
const findItemIdxById = function (items, id) {
2019-10-29 09:59:21 +01:00
return (items.map(function (item) { return item.id; })).indexOf(id);
2018-11-21 11:08:53 +01:00
};
2018-11-19 16:17:49 +01:00
/**
* Reinitialize the context of the search to display new results set
2018-11-19 16:17:49 +01:00
*/
const resetSearchMember = function () {
2018-11-21 11:08:53 +01:00
$scope.member.noMore = false;
$scope.member.page = 1;
2018-11-21 11:08:53 +01:00
};
2018-11-19 16:17:49 +01:00
/**
* Run a search query with the current parameters set ($scope.member[searchText,order,page])
* and affect or append the result in $scope.members, depending on the concat parameter
* @param [concat] {boolean} if true, the result will be appended to $scope.members instead of being replaced
2018-11-19 16:17:49 +01:00
*/
const memberSearch = function (concat) {
2018-11-20 12:26:06 +01:00
Member.list({
query: {
search: $scope.member.searchText,
order_by: $scope.member.order,
filter: $scope.member.memberFilter,
2018-11-20 12:26:06 +01:00
page: $scope.member.page,
size: USERS_PER_PAGE
}
}, function (members) {
if (concat) {
2018-11-21 11:08:53 +01:00
$scope.members = $scope.members.concat(members);
} else {
2018-11-21 11:08:53 +01:00
$scope.members = members;
}
if (!members[0] || (members[0].maxMembers <= $scope.members.length)) {
2018-11-21 11:08:53 +01:00
return $scope.member.noMore = true;
}
2018-11-21 11:08:53 +01:00
});
};
2016-03-23 18:39:41 +01:00
2018-11-19 16:17:49 +01:00
// !!! MUST BE CALLED AT THE END of the controller
2018-11-21 11:08:53 +01:00
return initialize();
}
2018-11-21 11:08:53 +01:00
]);
2016-03-23 18:39:41 +01:00
2018-11-19 16:17:49 +01:00
/**
* Controller used in the member edition page
*/
Application.Controllers.controller('EditMemberController', ['$scope', '$state', '$transition$', 'Member', 'Training', 'dialogs', 'growl', 'Group', 'Subscription', 'CSRF', 'memberPromise', 'tagsPromise', '$uibModal', 'Plan', '$filter', '_t', 'walletPromise', 'transactionsPromise', 'activeProviderPromise', 'Wallet', 'settingsPromise', 'ProofOfIdentityType',
function ($scope, $state, $transition$, Member, Training, dialogs, growl, Group, Subscription, CSRF, memberPromise, tagsPromise, $uibModal, Plan, $filter, _t, walletPromise, transactionsPromise, activeProviderPromise, Wallet, settingsPromise, ProofOfIdentityType) {
/* PUBLIC SCOPE */
2016-03-23 18:39:41 +01:00
2018-11-19 16:17:49 +01:00
// API URL where the form will be posted
2022-03-15 17:10:33 +01:00
$scope.actionUrl = `/api/members/${$transition$.params().id}`;
2016-03-23 18:39:41 +01:00
2018-11-19 16:17:49 +01:00
// Form action on the above URL
2018-11-21 11:08:53 +01:00
$scope.method = 'patch';
2016-03-23 18:39:41 +01:00
// List of tags joinable with user
2018-11-21 11:08:53 +01:00
$scope.tags = tagsPromise;
2016-03-23 18:39:41 +01:00
2018-11-19 16:17:49 +01:00
// The user to edit
$scope.user = cleanUser(memberPromise);
2016-03-23 18:39:41 +01:00
// Should the password be modified?
$scope.password = { change: false };
2016-03-23 18:39:41 +01:00
// is the phone number required in _member_form?
$scope.phoneRequired = (settingsPromise.phone_required === 'true');
// is the address required in _member_form?
$scope.addressRequired = (settingsPromise.address_required === 'true');
// is user validation required
$scope.enableUserValidationRequired = (settingsPromise.user_validation_required === 'true');
2018-11-19 16:17:49 +01:00
// the user subscription
if (($scope.user.subscribed_plan != null) && ($scope.user.subscription != null)) {
2018-11-21 11:08:53 +01:00
$scope.subscription = $scope.user.subscription;
} else {
Plan.query({ group_id: $scope.user.group_id }, function (plans) {
2018-11-21 11:08:53 +01:00
$scope.plans = plans;
2018-11-21 10:59:07 +01:00
return Array.from($scope.plans).map(function (plan) {
2018-11-21 11:08:53 +01:00
return (plan.nameToDisplay = $filter('humanReadablePlanName')(plan));
});
});
}
2016-03-23 18:39:41 +01:00
2018-11-19 16:17:49 +01:00
// Available trainings list
2018-11-21 11:08:53 +01:00
$scope.trainings = [];
2018-11-19 16:17:49 +01:00
// Profiles types (student/standard/...)
2018-11-21 11:08:53 +01:00
$scope.groups = [];
2018-11-19 16:17:49 +01:00
// the user wallet
2018-11-21 11:08:53 +01:00
$scope.wallet = walletPromise;
2018-11-19 16:17:49 +01:00
// user wallet transactions
2018-11-21 11:08:53 +01:00
$scope.transactions = transactionsPromise;
2018-11-19 16:17:49 +01:00
// used in wallet partial template to identify parent view
2018-11-21 11:08:53 +01:00
$scope.view = 'member_edit';
// current active authentication provider
2018-11-21 11:08:53 +01:00
$scope.activeProvider = activeProviderPromise;
// modal dialog to extend the current subscription for free
2021-10-11 18:50:53 +02:00
$scope.isOpenFreeExtendModal = false;
// modal dialog to renew the current subscription
$scope.isOpenRenewModal = false;
// modal dialog to take a new subscription
$scope.isOpenSubscribeModal = false;
/**
* Open a modal dialog asking for confirmation to change the role of the given user
* @returns {*}
*/
$scope.changeUserRole = function () {
const modalInstance = $uibModal.open({
animation: true,
templateUrl: '/admin/members/change_role_modal.html',
size: 'lg',
resolve: {
user () { return $scope.user; }
},
controller: ['$scope', '$uibModalInstance', 'Member', 'user', '_t', function ($scope, $uibModalInstance, Member, user, _t) {
$scope.user = user;
$scope.role = user.role;
$scope.roles = [
{ key: 'admin', label: _t('app.admin.members_edit.admin') },
{ key: 'manager', label: _t('app.admin.members_edit.manager'), notAnOption: (user.role === 'admin') },
{ key: 'member', label: _t('app.admin.members_edit.member'), notAnOption: (user.role === 'admin' || user.role === 'manager') }
];
$scope.ok = function () {
Member.updateRole(
{ id: $scope.user.id },
{ role: $scope.role },
function (_res) {
growl.success(_t('app.admin.members_edit.role_changed', { OLD: _t(`app.admin.members_edit.${user.role}`), NEW: _t(`app.admin.members_edit.${$scope.role}`) }));
return $uibModalInstance.close(_res);
},
function (error) {
growl.error(_t('app.admin.members_edit.error_while_changing_role'));
console.error(error);
}
);
};
$scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };
}]
});
// once the form was validated successfully ...
return modalInstance.result.then(function (user) {
// remove the user for the old list add to the new
});
};
2021-10-11 18:50:53 +02:00
/**
* Opens/closes the modal dialog to freely extend the subscription
*/
$scope.toggleFreeExtendModal = () => {
2021-10-12 14:07:35 +02:00
setTimeout(() => {
$scope.isOpenFreeExtendModal = !$scope.isOpenFreeExtendModal;
$scope.$apply();
}, 50);
2021-10-11 18:50:53 +02:00
};
/**
* Opens/closes the modal dialog to renew the subscription (with payment)
*/
$scope.toggleRenewModal = () => {
setTimeout(() => {
$scope.isOpenRenewModal = !$scope.isOpenRenewModal;
$scope.$apply();
}, 50);
};
/**
* Opens/closes the modal dialog to renew the subscription (with payment)
*/
$scope.toggleSubscribeModal = () => {
setTimeout(() => {
$scope.isOpenSubscribeModal = !$scope.isOpenSubscribeModal;
$scope.$apply();
}, 50);
};
2021-10-11 18:50:53 +02:00
/**
* Callback triggered if the subscription was successfully extended
*/
2021-10-12 14:07:35 +02:00
$scope.onExtendSuccess = (message, newExpirationDate) => {
growl.success(message);
$scope.subscription.expired_at = newExpirationDate;
2021-10-11 18:50:53 +02:00
};
/**
* Callback triggered if a new subscription was successfully taken
2021-10-11 18:50:53 +02:00
*/
$scope.onSubscribeSuccess = (message, newSubscription) => {
growl.success(message);
$scope.subscription = newSubscription;
2021-10-11 18:50:53 +02:00
};
/**
* Callback triggered if validate member was successfully taken
*/
$scope.onValidateMemberSuccess = (_user, message) => {
growl.success(message);
setTimeout(() => {
$scope.user = _user;
2022-05-11 18:06:49 +02:00
$scope.user.statistic_profile_attributes.birthday = moment(_user.statistic_profile_attributes.birthday).toDate();
$scope.$apply();
}, 50);
};
2018-11-19 16:17:49 +01:00
/**
* Callback triggered in case of error
2018-11-19 16:17:49 +01:00
*/
$scope.onError = (message) => {
growl.error(message);
2018-11-21 11:08:53 +01:00
};
/**
* Callback triggered when the user was successfully updated
*/
$scope.onUserSuccess = () => {
growl.success(_t('app.admin.members_edit.update_success'));
$state.go('app.admin.members');
};
/**
* Callback triggered in case of success
*/
$scope.onSuccess = (message) => {
growl.success(message);
};
$scope.createWalletCreditModal = function (user, wallet) {
const modalInstance = $uibModal.open({
animation: true,
templateUrl: '/wallet/credit_modal.html',
controller: ['$scope', '$uibModalInstance', 'Wallet', function ($scope, $uibModalInstance, Wallet) {
// default: do not generate a refund invoice
2018-11-21 11:08:53 +01:00
$scope.generate_avoir = false;
// date of the generated refund invoice
2018-11-21 11:08:53 +01:00
$scope.avoir_date = null;
// optional description shown on the refund invoice
2018-11-21 11:08:53 +01:00
$scope.description = '';
// default configuration for the avoir date selector widget
$scope.datePicker = {
format: Fablab.uibDateFormat,
opened: false,
options: {
startingDay: Fablab.weekStartingDay
}
2018-11-21 11:08:53 +01:00
};
2018-11-19 16:17:49 +01:00
/**
* Callback to open/close the date picker
*/
$scope.toggleDatePicker = function ($event) {
2018-11-21 11:08:53 +01:00
$event.preventDefault();
$event.stopPropagation();
return $scope.datePicker.opened = !$scope.datePicker.opened;
};
2017-10-04 18:56:39 +02:00
2018-11-19 16:17:49 +01:00
/**
* Modal dialog validation callback
*/
2018-11-21 10:59:07 +01:00
$scope.ok = function () {
2018-11-20 12:26:06 +01:00
Wallet.credit(
{ id: wallet.id },
{
amount: $scope.amount,
avoir: $scope.generate_avoir,
avoir_date: $scope.avoir_date,
avoir_description: $scope.description
},
function (_wallet) {
growl.success(_t('app.shared.wallet.wallet_credit_successfully'));
2018-11-21 11:08:53 +01:00
return $uibModalInstance.close(_wallet);
2018-11-20 12:26:06 +01:00
},
2018-11-21 10:59:07 +01:00
function (error) {
growl.error(_t('app.shared.wallet.a_problem_occurred_for_wallet_credit'));
2018-11-21 11:08:53 +01:00
console.error(error);
2018-11-20 12:26:06 +01:00
}
2018-11-21 11:08:53 +01:00
);
};
2018-11-19 16:17:49 +01:00
/**
* Modal dialog cancellation callback
*/
2018-11-21 11:08:53 +01:00
$scope.cancel = function () { $uibModalInstance.dismiss('cancel'); };
}
]
});
// once the form was validated successfully...
return modalInstance.result.then(function (wallet) {
2018-11-21 11:08:53 +01:00
$scope.wallet = wallet;
return Wallet.transactions({ id: wallet.id }, function (transactions) { $scope.transactions = transactions; });
});
};
2017-10-04 18:56:39 +02:00
2018-11-19 16:17:49 +01:00
/**
* To use as callback in Array.prototype.filter to get only enabled plans
*/
2018-11-21 11:08:53 +01:00
$scope.filterDisabledPlans = function (plan) { return !plan.disabled; };
2016-03-23 18:39:41 +01:00
/* PRIVATE SCOPE */
2016-03-23 18:39:41 +01:00
2018-11-19 16:17:49 +01:00
/**
* Kind of constructor: these actions will be realized first when the controller is loaded
*/
const initialize = function () {
2018-11-21 11:08:53 +01:00
CSRF.setMetaTags();
2016-03-23 18:39:41 +01:00
2018-11-19 16:17:49 +01:00
// the user subscription
if (($scope.user.subscribed_plan != null) && ($scope.user.subscription != null)) {
2018-11-21 11:08:53 +01:00
$scope.subscription = $scope.user.subscription;
} else {
Plan.query({ group_id: $scope.user.group_id }, function (plans) {
2018-11-21 11:08:53 +01:00
$scope.plans = plans;
2018-11-20 12:26:06 +01:00
return Array.from($scope.plans).map(function (plan) {
2018-11-21 11:08:53 +01:00
return (plan.nameToDisplay = `${plan.base_name} - ${plan.interval}`);
});
});
}
2016-03-23 18:39:41 +01:00
ProofOfIdentityType.query({ group_id: $scope.user.group_id }, function (proofOfIdentityTypes) {
$scope.hasProofOfIdentityTypes = proofOfIdentityTypes.length > 0;
});
// Using the MembersController
2018-11-21 11:08:53 +01:00
return new MembersController($scope, $state, Group, Training);
};
2016-03-23 18:39:41 +01:00
// prepare the user for the react-hook-form
function cleanUser (user) {
delete user.$promise;
delete user.$resolved;
return user;
}
2018-11-19 16:17:49 +01:00
// !!! MUST BE CALLED AT THE END of the controller
2018-11-21 11:08:53 +01:00
return initialize();
}
2018-11-21 11:08:53 +01:00
]);
2016-03-23 18:39:41 +01:00
2018-11-19 16:17:49 +01:00
/**
* Controller used in the member's creation page (admin view)
*/
Application.Controllers.controller('NewMemberController', ['$scope', '$state', 'Member', 'Training', 'Group', 'CSRF', 'settingsPromise', 'growl', '_t',
function ($scope, $state, Member, Training, Group, CSRF, settingsPromise, growl, _t) {
2018-11-21 11:08:53 +01:00
CSRF.setMetaTags();
2016-03-23 18:39:41 +01:00
/* PUBLIC SCOPE */
2016-03-23 18:39:41 +01:00
2018-11-19 16:17:49 +01:00
// API URL where the form will be posted
2018-11-21 11:08:53 +01:00
$scope.actionUrl = '/api/members';
2016-03-23 18:39:41 +01:00
2018-11-19 16:17:49 +01:00
// Form action on the above URL
2018-11-21 11:08:53 +01:00
$scope.method = 'post';
2016-03-23 18:39:41 +01:00
// Should the password be set manually or generated?
$scope.password = { change: false };
// is the phone number required in _member_form?
$scope.phoneRequired = (settingsPromise.phone_required === 'true');
// is the address required to sign-up?
$scope.addressRequired = (settingsPromise.address_required === 'true');
2018-11-19 16:17:49 +01:00
// Default member's profile parameters
$scope.user = {
plan_interval: '',
invoicing_profile_attributes: {},
statistic_profile_attributes: {}
};
2016-03-23 18:39:41 +01:00
// Callback when the admin check/uncheck the box telling that the new user is an organization.
2018-11-19 16:17:49 +01:00
// Disable or enable the organization fields in the form, accordingly
$scope.toggleOrganization = function () {
if ($scope.user.organization) {
if (!$scope.user.invoicing_profile_attributes) { $scope.user.invoicing_profile_attributes = {}; }
$scope.user.invoicing_profile_attributes.organization_attributes = {};
} else {
$scope.user.invoicing_profile_attributes.organization_attributes = undefined;
}
2018-11-21 11:08:53 +01:00
};
2016-03-23 18:39:41 +01:00
/**
* Callback triggered when the user was successfully updated
*/
$scope.onUserSuccess = () => {
growl.success(_t('app.admin.members_new.create_success'));
$state.go('app.admin.members');
};
/**
* Callback triggered in case of error
*/
$scope.onError = (message) => {
growl.error(message);
};
2018-11-19 16:17:49 +01:00
// Using the MembersController
2018-11-21 11:08:53 +01:00
return new MembersController($scope, $state, Group, Training);
}
2018-11-21 11:08:53 +01:00
]);
2016-03-23 18:39:41 +01:00
/**
* Controller used in the member's import page: import from CSV (admin view)
*/
2019-09-25 16:37:42 +02:00
Application.Controllers.controller('ImportMembersController', ['$scope', '$state', 'Group', 'Training', 'CSRF', 'tags', 'growl',
function ($scope, $state, Group, Training, CSRF, tags, growl) {
CSRF.setMetaTags();
/* PUBLIC SCOPE */
// API URL where the form will be posted
2019-09-25 16:37:42 +02:00
$scope.actionUrl = '/api/imports/members';
// Form action on the above URL
$scope.method = 'post';
// List of all tags
$scope.tags = tags;
2019-09-25 16:37:42 +02:00
/*
* Callback run after the form was submitted
* @param content {*} The result provided by the server, may be an Import object, or an error message
2019-09-25 16:37:42 +02:00
*/
$scope.onImportResult = function (content) {
2019-09-25 16:37:42 +02:00
if (content.id) {
$state.go('app.admin.members_import_result', { id: content.id });
} else {
growl.error(JSON.stringify(content));
2019-09-25 16:37:42 +02:00
}
};
2019-09-25 16:37:42 +02:00
// Using the MembersController
return new MembersController($scope, $state, Group, Training);
}
]);
2019-09-25 16:37:42 +02:00
/**
* Controller used in the member's import results page (admin view)
*/
Application.Controllers.controller('ImportMembersResultController', ['$scope', '$state', 'Import', 'importItem',
function ($scope, $state, Import, importItem) {
2019-09-25 16:37:42 +02:00
/* PUBLIC SCOPE */
// Current import as saved in database
$scope.import = importItem;
// Current import results
$scope.results = null;
2019-09-25 16:37:42 +02:00
/**
* Changes the view of the admin to the members import page
2019-09-25 16:37:42 +02:00
*/
$scope.cancel = function () { $state.go('app.admin.members_import'); };
/* PRIVATE SCOPE */
/**
* Kind of constructor: these actions will be realized first when the controller is loaded
*/
const initialize = function () {
$scope.results = JSON.parse($scope.import.results);
if (!$scope.results) {
setTimeout(function () {
Import.get({ id: $scope.import.id }, function (data) {
$scope.import = data;
initialize();
});
}, 5000);
}
};
// !!! MUST BE CALLED AT THE END of the controller
initialize();
2019-09-25 16:37:42 +02:00
}
]);
2018-11-19 16:17:49 +01:00
/**
* Controller used in the admin creation page (admin view)
2018-11-19 16:17:49 +01:00
*/
Application.Controllers.controller('NewAdminController', ['$state', '$scope', 'Admin', 'growl', '_t', 'settingsPromise',
function ($state, $scope, Admin, growl, _t, settingsPromise) {
2018-11-19 16:17:49 +01:00
// default admin profile
let getGender;
$scope.admin = {
statistic_profile_attributes: {
gender: true
},
profile_attributes: {},
invoicing_profile_attributes: {}
};
2016-03-23 18:39:41 +01:00
// Default parameters for AngularUI-Bootstrap datepicker
$scope.datePicker = {
format: Fablab.uibDateFormat,
opened: false,
options: {
startingDay: Fablab.weekStartingDay
}
};
// is the phone number required in _admin_form?
$scope.phoneRequired = (settingsPromise.phone_required === 'true');
// is the address required in _admin_form?
$scope.addressRequired = (settingsPromise.address_required === 'true');
2020-07-21 18:04:20 +02:00
/**
* Shows the birthday datepicker
2018-11-19 16:17:49 +01:00
*/
$scope.openDatePicker = function () { $scope.datePicker.opened = true; };
2016-03-23 18:39:41 +01:00
/**
2018-11-19 16:17:49 +01:00
* Send the new admin, currently stored in $scope.admin, to the server for database saving
*/
$scope.saveAdmin = function () {
Admin.save(
{},
{ admin: $scope.admin },
function () {
growl.success(_t('app.admin.admins_new.administrator_successfully_created_he_will_receive_his_connection_directives_by_email', { GENDER: getGender($scope.admin) }));
return $state.go('app.admin.members');
}
, function (error) {
growl.error(_t('app.admin.admins_new.failed_to_create_admin') + JSON.stringify(error.data ? error.data : error));
console.error(error);
}
);
};
2016-03-23 18:39:41 +01:00
/* PRIVATE SCOPE */
2016-03-23 18:39:41 +01:00
/**
2018-11-20 12:26:06 +01:00
* Return an enumerable meaningful string for the gender of the provider user
2018-11-19 16:17:49 +01:00
* @param user {Object} Database user record
* @return {string} 'male' or 'female'
*/
return getGender = function (user) {
if (user.statistic_profile_attributes) {
if (user.statistic_profile_attributes.gender) { return 'male'; } else { return 'female'; }
} else { return 'other'; }
};
}
2016-03-23 18:39:41 +01:00
2018-11-21 11:08:53 +01:00
]);
2020-04-21 17:24:22 +02:00
/**
* Controller used in the manager's creation page (admin view)
*/
2020-04-22 10:09:16 +02:00
Application.Controllers.controller('NewManagerController', ['$state', '$scope', 'User', 'groupsPromise', 'tagsPromise', 'growl', '_t',
function ($state, $scope, User, groupsPromise, tagsPromise, growl, _t) {
2020-04-21 17:24:22 +02:00
// default admin profile
$scope.manager = {
statistic_profile_attributes: {
gender: true
},
profile_attributes: {},
invoicing_profile_attributes: {}
};
2020-04-21 17:24:22 +02:00
// Default parameters for AngularUI-Bootstrap datepicker
$scope.datePicker = {
format: Fablab.uibDateFormat,
opened: false,
options: {
startingDay: Fablab.weekStartingDay
}
};
2020-04-22 10:09:16 +02:00
// list of all groups
$scope.groups = groupsPromise.filter(function (g) { return (g.slug !== 'admins') && !g.disabled; });
// list of all tags
$scope.tags = tagsPromise;
2020-04-22 10:09:16 +02:00
/**
* Shows the birthday datepicker
2020-04-21 17:24:22 +02:00
*/
$scope.openDatePicker = function () { $scope.datePicker.opened = true; };
2020-04-21 17:24:22 +02:00
/**
2020-04-21 17:24:22 +02:00
* Send the new manager, currently stored in $scope.manager, to the server for database saving
*/
$scope.saveManager = function () {
User.save(
{},
{ manager: $scope.manager },
function () {
growl.success(_t('app.admin.manager_new.manager_successfully_created', { GENDER: getGender($scope.manager) }));
return $state.go('app.admin.members');
}
, function (error) {
growl.error(_t('app.admin.admins_new.failed_to_create_manager') + JSON.stringify(error.data ? error.data : error));
console.error(error);
}
);
};
2020-04-21 17:24:22 +02:00
/* PRIVATE SCOPE */
2020-04-21 17:24:22 +02:00
/**
2020-04-21 17:24:22 +02:00
* Return an enumerable meaningful string for the gender of the provider user
* @param user {Object} Database user record
* @return {string} 'male' or 'female'
*/
const getGender = function (user) {
if (user.statistic_profile_attributes) {
if (user.statistic_profile_attributes.gender) { return 'male'; } else { return 'female'; }
} else { return 'other'; }
};
}
2020-04-21 17:24:22 +02:00
]);