Merge pull request #2749 from FinnStutzenstein/Issue2666
changing user import (closes #2666)
This commit is contained in:
commit
358fd59d3c
@ -91,12 +91,12 @@
|
|||||||
{{ motion.text | limitTo:80 }}{{ motion.text.length > 80 ? '...' : '' }}
|
{{ motion.text | limitTo:80 }}{{ motion.text.length > 80 ? '...' : '' }}
|
||||||
<td>{{ motion.reason | limitTo:80 }}{{ motion.reason.length > 80 ? '...' : '' }}
|
<td>{{ motion.reason | limitTo:80 }}{{ motion.reason.length > 80 ? '...' : '' }}
|
||||||
<td ng-class="{ 'text-warning': motion.submitter_create }">
|
<td ng-class="{ 'text-warning': motion.submitter_create }">
|
||||||
<span ng-if="motion.submitter_create" title="{{ motion.submitter_create | translate }}" class="pointer">
|
<span ng-if="motion.submitter_create" title="{{ motion.submitter_create | translate }}">
|
||||||
<i class="fa fa-plus-circle"></i>
|
<i class="fa fa-plus-circle"></i>
|
||||||
</span>
|
</span>
|
||||||
{{ motion.submitter }}
|
{{ motion.submitter }}
|
||||||
<td ng-class="{ 'text-warning': motion.category_create }">
|
<td ng-class="{ 'text-warning': motion.category_create }">
|
||||||
<span ng-if="motion.category_create" title="{{ motion.category_create | translate }}" class="pointer">
|
<span ng-if="motion.category_create" title="{{ motion.category_create | translate }}">
|
||||||
<i class="fa fa-plus-circle"></i>
|
<i class="fa fa-plus-circle"></i>
|
||||||
</span>
|
</span>
|
||||||
{{ motion.category }}
|
{{ motion.category }}
|
||||||
@ -129,7 +129,7 @@
|
|||||||
<button ng-click="clear()" class="btn btn-default" translate>
|
<button ng-click="clear()" class="btn btn-default" translate>
|
||||||
Clear preview
|
Clear preview
|
||||||
</button>
|
</button>
|
||||||
<button ng-if="!csvImporting" ng-click="import()" class="btn btn-primary" translate>
|
<button ng-if="!csvImporting && (motions.length - motionsFailed.length) > 0" ng-click="import()" class="btn btn-primary" translate>
|
||||||
Import {{ motions.length - motionsFailed.length }} motions
|
Import {{ motions.length - motionsFailed.length }} motions
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -133,7 +133,7 @@
|
|||||||
<button ng-click="clear()" class="btn btn-default" translate>
|
<button ng-click="clear()" class="btn btn-default" translate>
|
||||||
Clear preview
|
Clear preview
|
||||||
</button>
|
</button>
|
||||||
<button ng-if="!csvImporting" ng-click="import()" class="btn btn-primary" translate>
|
<button ng-if="!csvImporting && (items.length - itemdFailed.length) > 0" ng-click="import()" class="btn btn-primary" translate>
|
||||||
Import {{ items.length - itemsFailed.length }} topics
|
Import {{ items.length - itemsFailed.length }} topics
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,30 +5,62 @@
|
|||||||
angular.module('OpenSlidesApp.users.csv', [])
|
angular.module('OpenSlidesApp.users.csv', [])
|
||||||
|
|
||||||
.factory('UserCsvExport', [
|
.factory('UserCsvExport', [
|
||||||
function () {
|
'Group',
|
||||||
return function (element, users) {
|
'gettextCatalog',
|
||||||
var csvRows = [
|
function (Group, gettextCatalog) {
|
||||||
['title', 'first_name', 'last_name', 'structure_level', 'number', 'groups', 'comment', 'is_active', 'is_present', 'is_committee'],
|
return {
|
||||||
];
|
export: function (element, users) {
|
||||||
_.forEach(users, function (user) {
|
var csvRows = [
|
||||||
var row = [];
|
['title', 'first_name', 'last_name', 'structure_level', 'number', 'groups', 'comment', 'is_active', 'is_present', 'is_committee'],
|
||||||
row.push('"' + user.title + '"');
|
];
|
||||||
row.push('"' + user.first_name + '"');
|
_.forEach(users, function (user) {
|
||||||
row.push('"' + user.last_name + '"');
|
var row = [];
|
||||||
row.push('"' + user.structure_level + '"');
|
row.push('"' + user.title + '"');
|
||||||
row.push('"' + user.number + '"');
|
row.push('"' + user.first_name + '"');
|
||||||
row.push('"' + user.groups_id.join(',') + '"');
|
row.push('"' + user.last_name + '"');
|
||||||
row.push('"' + user.comment + '"');
|
row.push('"' + user.structure_level + '"');
|
||||||
row.push(user.is_active ? '1' : '0');
|
row.push('"' + user.number + '"');
|
||||||
row.push(user.is_present ? '1' : '0');
|
row.push('"' + user.groups_id.join(',') + '"');
|
||||||
row.push(user.is_committee ? '1' : '0');
|
row.push('"' + user.comment + '"');
|
||||||
csvRows.push(row);
|
row.push(user.is_active ? '1' : '0');
|
||||||
});
|
row.push(user.is_present ? '1' : '0');
|
||||||
|
row.push(user.is_committee ? '1' : '0');
|
||||||
|
csvRows.push(row);
|
||||||
|
});
|
||||||
|
|
||||||
var csvString = csvRows.join("%0A");
|
var csvString = csvRows.join("%0A");
|
||||||
element.href = 'data:text/csv;charset=utf-8,' + csvString;
|
element.href = 'data:text/csv;charset=utf-8,' + csvString;
|
||||||
element.download = 'users-export.csv';
|
element.download = 'users-export.csv';
|
||||||
element.target = '_blank';
|
element.target = '_blank';
|
||||||
|
},
|
||||||
|
|
||||||
|
downloadExample: function (element) {
|
||||||
|
// try to get an example with two groups and one with one group
|
||||||
|
var groups = Group.getAll();
|
||||||
|
var csvGroups = '';
|
||||||
|
var csvGroup = '';
|
||||||
|
if (groups.length >= 3) { // do not pick groups[0], this is the default group
|
||||||
|
csvGroups = '"' + gettextCatalog.getString(groups[1].name) +
|
||||||
|
', ' + gettextCatalog.getString(groups[2].name) + '"';
|
||||||
|
}
|
||||||
|
if (groups.length >= 2) {
|
||||||
|
csvGroup = gettextCatalog.getString(groups[groups.length - 1].name); // take last group
|
||||||
|
}
|
||||||
|
var csvRows = [
|
||||||
|
// column header line
|
||||||
|
['title', 'first_name', 'last_name', 'structure_level', 'number', 'groups', 'comment', 'is_active', 'is_present', 'is_committee'],
|
||||||
|
// example entries
|
||||||
|
['Dr.', 'Max', 'Mustermann', 'Berlin','1234567890', csvGroups, 'xyz', '1', '1', ''],
|
||||||
|
['', 'John', 'Doe', 'Washington','75/99/8-2', csvGroup, 'abc', '1', '1', ''],
|
||||||
|
['', 'Fred', 'Bloggs', 'London', '', '', '', '', '', ''],
|
||||||
|
['', '', 'Executive Board', '', '', '', '', '', '', '1'],
|
||||||
|
|
||||||
|
];
|
||||||
|
var csvString = csvRows.join("%0A");
|
||||||
|
element.href = 'data:text/csv;charset=utf-8,' + csvString;
|
||||||
|
element.download = 'users-example.csv';
|
||||||
|
element.target = '_blank';
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
@ -682,7 +682,7 @@ angular.module('OpenSlidesApp.users.site', [
|
|||||||
// Export as a csv file
|
// Export as a csv file
|
||||||
$scope.csvExport = function () {
|
$scope.csvExport = function () {
|
||||||
var element = document.getElementById('downloadLinkCSV');
|
var element = document.getElementById('downloadLinkCSV');
|
||||||
UserCsvExport(element, $scope.usersFiltered);
|
UserCsvExport.export(element, $scope.usersFiltered);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
@ -886,7 +886,8 @@ angular.module('OpenSlidesApp.users.site', [
|
|||||||
'gettextCatalog',
|
'gettextCatalog',
|
||||||
'User',
|
'User',
|
||||||
'Group',
|
'Group',
|
||||||
function($scope, $q, gettext, gettextCatalog, User, Group) {
|
'UserCsvExport',
|
||||||
|
function($scope, $q, gettext, gettextCatalog, User, Group, UserCsvExport) {
|
||||||
// import from textarea
|
// import from textarea
|
||||||
$scope.importByLine = function () {
|
$scope.importByLine = function () {
|
||||||
$scope.usernames = $scope.userlist[0].split("\n");
|
$scope.usernames = $scope.userlist[0].split("\n");
|
||||||
@ -984,24 +985,29 @@ angular.module('OpenSlidesApp.users.site', [
|
|||||||
user.number = "";
|
user.number = "";
|
||||||
}
|
}
|
||||||
// groups
|
// groups
|
||||||
|
user.groups_id = []; // will be overwritten if there are groups
|
||||||
if (user.groups) {
|
if (user.groups) {
|
||||||
var csvGroups = user.groups.replace(quotionRe, '$1').split(",");
|
user.groups = user.groups.replace(quotionRe, '$1').split(',');
|
||||||
user.groups_id = [];
|
user.groups = _.map(user.groups, function (group) {
|
||||||
user.groupnames = [];
|
return _.trim(group); // remove whitespaces on start or end
|
||||||
if (csvGroups !== '') {
|
});
|
||||||
// All group objects are already loaded via the resolve statement from ui-router.
|
|
||||||
var allGroups = Group.getAll();
|
// All group objects are already loaded via the resolve statement from ui-router.
|
||||||
csvGroups.forEach(function(csvGroup) {
|
var allGroups = Group.getAll();
|
||||||
allGroups.forEach(function (allGroup) {
|
// in allGroupsNames ar all original group names and translated names if a
|
||||||
if (csvGroup == allGroup.id) {
|
// translation exists (e.g. for default group Delegates)
|
||||||
user.groups_id.push(allGroup.id);
|
var allGroupsNames = [];
|
||||||
user.groupnames.push(allGroup.name);
|
_.forEach(allGroups, function (group) {
|
||||||
}
|
var groupTranslation = gettextCatalog.getString(group.name);
|
||||||
});
|
if (group.name !== groupTranslation) {
|
||||||
});
|
allGroupsNames.push(groupTranslation);
|
||||||
}
|
}
|
||||||
} else {
|
allGroupsNames.push(group.name);
|
||||||
user.groups_id = [];
|
});
|
||||||
|
user.groupsToCreate = _.difference(user.groups, allGroupsNames);
|
||||||
|
|
||||||
|
// for template:
|
||||||
|
user.groupsNotToCreate = _.difference(user.groups, user.groupsToCreate);
|
||||||
}
|
}
|
||||||
// comment
|
// comment
|
||||||
if (user.comment) {
|
if (user.comment) {
|
||||||
@ -1106,39 +1112,79 @@ angular.module('OpenSlidesApp.users.site', [
|
|||||||
// import from csv file
|
// import from csv file
|
||||||
$scope.import = function () {
|
$scope.import = function () {
|
||||||
$scope.csvImporting = true;
|
$scope.csvImporting = true;
|
||||||
var existingUsers = User.getAll();
|
|
||||||
angular.forEach($scope.users, function (user) {
|
// collect all needed groups and create non existing groups
|
||||||
if (!user.importerror) {
|
var groupsToCreate = [];
|
||||||
// Do nothing on duplicateAction==duplicateActions[0] (keep original)
|
_.forEach($scope.users, function (user) {
|
||||||
if (user.duplicate && (user.duplicateAction == $scope.duplicateActions[1])) {
|
if (!user.importerror && user.groups.length) {
|
||||||
// delete existing user
|
_.forEach(user.groupsToCreate, function (group) { // Just append groups, that are not listed yet.
|
||||||
var deletePromises = [];
|
if (_.indexOf(groupsToCreate, group) == -1) {
|
||||||
existingUsers.forEach(function(user_) {
|
groupsToCreate.push(group);
|
||||||
if (user_.first_name == user.first_name &&
|
}
|
||||||
user_.last_name == user.last_name &&
|
});
|
||||||
user_.structure_level == user.structure_level) {
|
}
|
||||||
deletePromises.push(User.destroy(user_.id));
|
});
|
||||||
}
|
var createPromises = [];
|
||||||
|
$scope.groupsCreated = 0;
|
||||||
|
_.forEach(groupsToCreate, function (groupname) {
|
||||||
|
var group = {
|
||||||
|
name: groupname,
|
||||||
|
permissions: []
|
||||||
|
};
|
||||||
|
createPromises.push(Group.create(group).then( function (success) {
|
||||||
|
$scope.groupsCreated++;
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
$q.all(createPromises).then(function () {
|
||||||
|
// reload allGroups, now all new groups are created
|
||||||
|
var allGroups = Group.getAll();
|
||||||
|
var existingUsers = User.getAll();
|
||||||
|
|
||||||
|
_.forEach($scope.users, function (user) {
|
||||||
|
if (!user.importerror) {
|
||||||
|
// Assign all groups
|
||||||
|
_.forEach(user.groups, function(csvGroup) {
|
||||||
|
allGroups.forEach(function (allGroup) {
|
||||||
|
// check with and without translation
|
||||||
|
if (csvGroup === allGroup.name ||
|
||||||
|
csvGroup === gettextCatalog.getString(allGroup.name)) {
|
||||||
|
user.groups_id.push(allGroup.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
$q.all(deletePromises).then(function() {
|
|
||||||
|
// Do nothing on duplicateAction==duplicateActions[0] (keep original)
|
||||||
|
if (user.duplicate && (user.duplicateAction == $scope.duplicateActions[1])) {
|
||||||
|
// delete existing user
|
||||||
|
var deletePromises = [];
|
||||||
|
existingUsers.forEach(function(user_) {
|
||||||
|
if (user_.first_name == user.first_name &&
|
||||||
|
user_.last_name == user.last_name &&
|
||||||
|
user_.structure_level == user.structure_level) {
|
||||||
|
deletePromises.push(User.destroy(user_.id));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$q.all(deletePromises).then(function() {
|
||||||
|
User.create(user).then(
|
||||||
|
function(success) {
|
||||||
|
user.imported = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} else if (!user.duplicate ||
|
||||||
|
(user.duplicateAction == $scope.duplicateActions[2])) {
|
||||||
|
// create user
|
||||||
User.create(user).then(
|
User.create(user).then(
|
||||||
function(success) {
|
function(success) {
|
||||||
user.imported = true;
|
user.imported = true;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
} else if (!user.duplicate ||
|
|
||||||
(user.duplicateAction == $scope.duplicateActions[2])) {
|
|
||||||
// create user
|
|
||||||
User.create(user).then(
|
|
||||||
function(success) {
|
|
||||||
user.imported = true;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
$scope.csvimported = true;
|
||||||
});
|
});
|
||||||
$scope.csvimported = true;
|
|
||||||
};
|
};
|
||||||
$scope.clear = function () {
|
$scope.clear = function () {
|
||||||
$scope.csv.result = null;
|
$scope.csv.result = null;
|
||||||
@ -1146,20 +1192,7 @@ angular.module('OpenSlidesApp.users.site', [
|
|||||||
// download CSV example file
|
// download CSV example file
|
||||||
$scope.downloadCSVExample = function () {
|
$scope.downloadCSVExample = function () {
|
||||||
var element = document.getElementById('downloadLink');
|
var element = document.getElementById('downloadLink');
|
||||||
var csvRows = [
|
UserCsvExport.downloadExample(element);
|
||||||
// column header line
|
|
||||||
['title', 'first_name', 'last_name', 'structure_level', 'number', 'groups', 'comment', 'is_active', 'is_present', 'is_committee'],
|
|
||||||
// example entries
|
|
||||||
['Dr.', 'Max', 'Mustermann', 'Berlin','1234567890', '"3,4"', 'xyz', '1', '1', ''],
|
|
||||||
['', 'John', 'Doe', 'Washington','75/99/8-2', '3', 'abc', '1', '1', ''],
|
|
||||||
['', 'Fred', 'Bloggs', 'London', '', '', '', '', '', ''],
|
|
||||||
['', '', 'Executive Board', '', '', '5', '', '', '', '1'],
|
|
||||||
|
|
||||||
];
|
|
||||||
var csvString = csvRows.join("%0A");
|
|
||||||
element.href = 'data:text/csv;charset=utf-8,' + csvString;
|
|
||||||
element.download = 'users-example.csv';
|
|
||||||
element.target = '_blank';
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
@ -69,10 +69,6 @@
|
|||||||
<ul class="indentation">
|
<ul class="indentation">
|
||||||
<li><translate>Required comma or semicolon separated values with these column header names in the first row</translate>:<br>
|
<li><translate>Required comma or semicolon separated values with these column header names in the first row</translate>:<br>
|
||||||
<code>title, first_name, last_name, structure_level, number, groups, comment, is_active, is_present, is_committee</code>
|
<code>title, first_name, last_name, structure_level, number, groups, comment, is_active, is_present, is_committee</code>
|
||||||
<li><translate>Default groups</translate>:
|
|
||||||
<translate>Delegates</translate> <code>2</code>,
|
|
||||||
<translate>Staff</translate> <code>3</code>
|
|
||||||
<translate>Committees</translate> <code>4</code>
|
|
||||||
<li translate>At least given name or surname have to be filled in. All
|
<li translate>At least given name or surname have to be filled in. All
|
||||||
other fields are optional and may be empty.
|
other fields are optional and may be empty.
|
||||||
<li translate>Only double quotes are accepted as text delimiter (no single quotes).
|
<li translate>Only double quotes are accepted as text delimiter (no single quotes).
|
||||||
@ -102,14 +98,15 @@
|
|||||||
<strong class="text-danger" ng-if="duplicates > 1">{{ duplicates }} <translate>duplicates</translate></strong>
|
<strong class="text-danger" ng-if="duplicates > 1">{{ duplicates }} <translate>duplicates</translate></strong>
|
||||||
|
|
||||||
<div uib-dropdown>
|
<div uib-dropdown>
|
||||||
<button type="button" class="btn btn-default btn-danger btn-sm" uib-dropdown-toggle>
|
<button id="GlobalAction" type="button" class="btn btn-default btn-danger btn-sm" uib-dropdown-toggle>
|
||||||
<translate>Set global action</translate>
|
<translate>Set global action</translate>
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu dropdown-entries">
|
<ul class="dropdown-menu" aria-labelledby="GlobalAction">
|
||||||
<li role="menuitem" ng-repeat="action in duplicateActions" class="pointer"
|
<li ng-repeat="action in duplicateActions">
|
||||||
ng-click="setGlobalAction(action)">
|
<a href ng-click="setGlobalAction(action)">
|
||||||
{{ action | translate }}
|
{{ action | translate }}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -146,7 +143,11 @@
|
|||||||
<td>
|
<td>
|
||||||
{{ user.number }}
|
{{ user.number }}
|
||||||
<td>
|
<td>
|
||||||
<div ng-repeat="groupname in user.groupnames">
|
<div ng-repeat="groupname in user.groupsNotToCreate">
|
||||||
|
{{ groupname | translate }}
|
||||||
|
</div>
|
||||||
|
<div ng-repeat="groupname in user.groupsToCreate" class="text-warning">
|
||||||
|
<i class="fa fa-plus-circle"></i>
|
||||||
{{ groupname | translate }}
|
{{ groupname | translate }}
|
||||||
</div>
|
</div>
|
||||||
<td style="max-width: 130px;">
|
<td style="max-width: 130px;">
|
||||||
@ -164,16 +165,17 @@
|
|||||||
ng-click="user.is_committee = !user.is_committee"></i>
|
ng-click="user.is_committee = !user.is_committee"></i>
|
||||||
<td ng-if="duplicates > 0">
|
<td ng-if="duplicates > 0">
|
||||||
<div ng-if="user.duplicate" uib-tooltip="{{ user.duplicate_info }}" uib-dropdown>
|
<div ng-if="user.duplicate" uib-tooltip="{{ user.duplicate_info }}" uib-dropdown>
|
||||||
<button type="button" class="btn btn-default btn-sm"
|
<button id="UserAction{{ $index }}" type="button" class="btn btn-default btn-sm"
|
||||||
uib-dropdown-toggle ng-class="user.duplicateAction == duplicateActions[0] ? 'btn-warning' : (user.duplicateAction == duplicateActions[1] ? 'btn-danger' : 'btn-success')">
|
uib-dropdown-toggle ng-class="user.duplicateAction == duplicateActions[0] ? 'btn-warning' : (user.duplicateAction == duplicateActions[1] ? 'btn-danger' : 'btn-success')">
|
||||||
{{ user.duplicateAction | translate }}
|
{{ user.duplicateAction | translate }}
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu dropdown-entries">
|
<ul class="dropdown-menu" aria-labelledby="UserAction{{ $index }}">
|
||||||
<li role="menuitem" ng-repeat="action in duplicateActions" class="pointer"
|
<li ng-repeat="action in duplicateActions">
|
||||||
ng-click="user.duplicateAction = action; calcStats()">
|
<a href ng-click="user.duplicateAction = action; calcStats()">
|
||||||
<i class="fa fa-check" ng-if="user.duplicateAction == action"></i>
|
<i class="fa fa-check" ng-if="user.duplicateAction == action"></i>
|
||||||
{{ action | translate }}
|
{{ action | translate }}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</table>
|
</table>
|
||||||
@ -206,13 +208,14 @@
|
|||||||
<i class="fa fa-check-circle fa-lg"></i>
|
<i class="fa fa-check-circle fa-lg"></i>
|
||||||
{{ usersImported.length }}
|
{{ usersImported.length }}
|
||||||
<translate>participants were successfully imported.</translate>
|
<translate>participants were successfully imported.</translate>
|
||||||
|
(<translate>Groups created</translate>: {{ groupsCreated }})
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="spacer">
|
<div class="spacer">
|
||||||
<button ng-click="clear()" class="btn btn-default" translate>
|
<button ng-click="clear()" class="btn btn-default" translate>
|
||||||
Clear preview
|
Clear preview
|
||||||
</button>
|
</button>
|
||||||
<button ng-if="!csvImporting" ng-click="import()" class="btn btn-primary" translate>
|
<button ng-if="!csvImporting && usersWillBeImported > 0" ng-click="import()" class="btn btn-primary" translate>
|
||||||
Import {{ usersWillBeImported }} participants
|
Import {{ usersWillBeImported }} participants
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user