Skip to content

Commit 161ee0f

Browse files
authored
Merge pull request #964 from amosfolz/issue-#867
Allow null group assignment for users (Issue #867)
2 parents 0e3734b + 71b2cd1 commit 161ee0f

6 files changed

Lines changed: 107 additions & 41 deletions

File tree

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
/*
4+
* UserFrosting (http://www.userfrosting.com)
5+
*
6+
* @link https://github.com/userfrosting/UserFrosting
7+
* @copyright Copyright (c) 2019 Alexander Weissman
8+
* @license https://github.com/userfrosting/UserFrosting/blob/master/LICENSE.md (MIT License)
9+
*/
10+
11+
namespace UserFrosting\Sprinkle\Account\Database\Migrations\v430;
12+
13+
use Illuminate\Database\Schema\Blueprint;
14+
use UserFrosting\Sprinkle\Core\Database\Migration;
15+
16+
/**
17+
* Groups table migration
18+
* Changes `group_id` column properties to allow user to be created without a group.
19+
* Version 4.3.0.
20+
*
21+
* See https://laravel.com/docs/5.4/migrations#tables
22+
*
23+
* @author Amos Folz
24+
*/
25+
class UpdateUsersTable extends Migration
26+
{
27+
/**
28+
* {@inheritdoc}
29+
*/
30+
public static $dependencies = [
31+
'\UserFrosting\Sprinkle\Account\Database\Migrations\v400\GroupsTable',
32+
'\UserFrosting\Sprinkle\Account\Database\Migrations\v400\UsersTable',
33+
'\UserFrosting\Sprinkle\Account\Database\Migrations\v420\AddingForeignKeys',
34+
];
35+
36+
/**
37+
* {@inheritdoc}
38+
*/
39+
public function up()
40+
{
41+
if ($this->schema->hasTable('users')) {
42+
$this->schema->table('users', function (Blueprint $table) {
43+
$table->unsignedInteger('group_id')->default(null)->comment('The id of the user group.')->nullable()->change();
44+
});
45+
}
46+
}
47+
48+
/**
49+
* {@inheritdoc}
50+
*/
51+
public function down()
52+
{
53+
$this->schema->table('users', function (Blueprint $table) {
54+
$table->unsignedInteger('group_id')->default(1)->comment('The id of the user group.')->change();
55+
});
56+
}
57+
}

app/sprinkles/admin/assets/userfrosting/js/widgets/users.js

Lines changed: 42 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Set up the form in a modal after being successfully attached to the body.
77
*/
88
function attachUserForm() {
9-
$("body").on('renderSuccess.ufModal', function (data) {
9+
$("body").on('renderSuccess.ufModal', function(data) {
1010
var modal = $(this).ufModal('getModal');
1111
var form = modal.find('.js-form');
1212

@@ -15,6 +15,8 @@ function attachUserForm() {
1515
width: '100%'
1616
});
1717

18+
19+
1820
// Set up the form for submission
1921
form.ufForm({
2022
validator: page.validators
@@ -42,14 +44,14 @@ function toggleChangePasswordMode(el, userName, changePasswordMode) {
4244
if (validator) {
4345
//Iterate through named elements inside of the form, and mark them as error free
4446
el.find("input[type='password']").each(function() {
45-
validator.successList.push(this); //mark as error free
47+
validator.successList.push(this); //mark as error free
4648
});
47-
validator.resetForm();//remove error class on name elements and clear history
48-
validator.reset();//remove all error and success data
49+
validator.resetForm(); //remove error class on name elements and clear history
50+
validator.reset(); //remove all error and success data
4951
}
5052
el.find("input[type='password']").closest('.form-group')
51-
.removeClass('has-error has-success');
52-
el.find('.form-control-feedback').each(function () {
53+
.removeClass('has-error has-success');
54+
el.find('.form-control-feedback').each(function() {
5355
$(this).remove();
5456
});
5557
} else {
@@ -66,7 +68,7 @@ function toggleChangePasswordMode(el, userName, changePasswordMode) {
6668
* Update user field(s)
6769
*/
6870
function updateUser(userName, fieldName, fieldValue) {
69-
var data = {
71+
var data = {
7072
'value': fieldValue
7173
};
7274

@@ -92,19 +94,19 @@ function updateUser(userName, fieldName, fieldValue) {
9294
return $.parseJSON(result);
9395
}
9496
} catch (e) {
95-
// statements to handle any exceptions
96-
console.log("Warning: Could not parse expected JSON response.");
97-
return {};
97+
// statements to handle any exceptions
98+
console.log("Warning: Could not parse expected JSON response.");
99+
return {};
98100
}
99101
}
100102
}
101-
}).fail(function (jqXHR) {
103+
}).fail(function(jqXHR) {
102104
// Error messages
103105
if (debugAjax && jqXHR.responseText) {
104106
document.write(jqXHR.responseText);
105107
document.close();
106108
} else {
107-
console.log("Error (" + jqXHR.status + "): " + jqXHR.responseText );
109+
console.log("Error (" + jqXHR.status + "): " + jqXHR.responseText);
108110

109111
// Display errors on failure
110112
// TODO: ufAlerts widget should have a 'destroy' method
@@ -113,12 +115,12 @@ function updateUser(userName, fieldName, fieldValue) {
113115
} else {
114116
$("#alerts-page").ufAlerts('clear');
115117
}
116-
118+
117119
$("#alerts-page").ufAlerts('fetch').ufAlerts('render');
118120
}
119121

120122
return jqXHR;
121-
}).done(function (response) {
123+
}).done(function(response) {
122124
window.location.reload();
123125
});
124126
}
@@ -128,8 +130,8 @@ function updateUser(userName, fieldName, fieldValue) {
128130
* @param {module:jQuery} el jQuery wrapped element to target.
129131
* @param {{delete_redirect: string}} options Options used to modify behaviour of button actions.
130132
*/
131-
function bindUserButtons(el, options) {
132-
if (!options) options = {};
133+
function bindUserButtons(el, options) {
134+
if (!options) options = {};
133135

134136
/**
135137
* Buttons that launch a modal dialog
@@ -162,38 +164,38 @@ function updateUser(userName, fieldName, fieldValue) {
162164
msgTarget: $("#alerts-page")
163165
});
164166

165-
$("body").on('renderSuccess.ufModal', function (data) {
167+
$("body").on('renderSuccess.ufModal', function(data) {
166168
var modal = $(this).ufModal('getModal');
167169
var form = modal.find('.js-form');
168170

169171
// Set up collection widget
170172
var roleWidget = modal.find('.js-form-roles');
171173
roleWidget.ufCollection({
172-
dropdown : {
174+
dropdown: {
173175
ajax: {
174-
url : site.uri.public + '/api/roles'
176+
url: site.uri.public + '/api/roles'
175177
},
176-
placeholder : "Select a role"
178+
placeholder: "Select a role"
177179
},
178180
dropdownTemplate: modal.find('#user-roles-select-option').html(),
179-
rowTemplate : modal.find('#user-roles-row').html()
181+
rowTemplate: modal.find('#user-roles-row').html()
180182
});
181183

182184
// Get current roles and add to widget
183185
$.getJSON(site.uri.public + '/api/users/u/' + userName + '/roles')
184-
.done(function (data) {
185-
$.each(data.rows, function (idx, role) {
186-
role.text = role.name;
187-
roleWidget.ufCollection('addRow', role);
186+
.done(function(data) {
187+
$.each(data.rows, function(idx, role) {
188+
role.text = role.name;
189+
roleWidget.ufCollection('addRow', role);
190+
});
188191
});
189-
});
190192

191193
// Set up form for submission
192194
form.ufForm()
193-
.on("submitSuccess.ufForm", function() {
194-
// Reload page on success
195-
window.location.reload();
196-
});
195+
.on("submitSuccess.ufForm", function() {
196+
// Reload page on success
197+
window.location.reload();
198+
});
197199
});
198200
});
199201

@@ -210,7 +212,7 @@ function updateUser(userName, fieldName, fieldValue) {
210212
msgTarget: $("#alerts-page")
211213
});
212214

213-
$("body").on('renderSuccess.ufModal', function () {
215+
$("body").on('renderSuccess.ufModal', function() {
214216
var modal = $(this).ufModal('getModal');
215217
var form = modal.find('.js-form');
216218

@@ -246,16 +248,16 @@ function updateUser(userName, fieldName, fieldValue) {
246248
msgTarget: $("#alerts-page")
247249
});
248250

249-
$("body").on('renderSuccess.ufModal', function () {
251+
$("body").on('renderSuccess.ufModal', function() {
250252
var modal = $(this).ufModal('getModal');
251253
var form = modal.find('.js-form');
252254

253255
form.ufForm()
254-
.on("submitSuccess.ufForm", function() {
255-
// Navigate or reload page on success
256-
if (options.delete_redirect) window.location.href = options.delete_redirect;
257-
else window.location.reload();
258-
});
256+
.on("submitSuccess.ufForm", function() {
257+
// Navigate or reload page on success
258+
if (options.delete_redirect) window.location.href = options.delete_redirect;
259+
else window.location.reload();
260+
});
259261
});
260262
});
261263

@@ -269,12 +271,12 @@ function updateUser(userName, fieldName, fieldValue) {
269271
updateUser(btn.data('user_name'), 'flag_verified', '1');
270272
});
271273

272-
el.find('.js-user-enable').click(function () {
274+
el.find('.js-user-enable').click(function() {
273275
var btn = $(this);
274276
updateUser(btn.data('user_name'), 'flag_enabled', '1');
275277
});
276278

277-
el.find('.js-user-disable').click(function () {
279+
el.find('.js-user-disable').click(function() {
278280
var btn = $(this);
279281
updateUser(btn.data('user_name'), 'flag_enabled', '0');
280282
});
@@ -292,4 +294,4 @@ function bindUserCreationButton(el) {
292294

293295
attachUserForm();
294296
});
295-
};
297+
};

app/sprinkles/admin/locale/en_US/messages.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
'MANAGE' => 'Manage group',
6060
'NAME' => 'Group name',
6161
'NAME_EXPLAIN' => 'Please enter a name for the group',
62+
'NONE' => 'No group',
6263
'NOT_EMPTY' => "You can't do that because there are still users associated with the group <strong>{{name}}</strong>.",
6364
'PAGE_DESCRIPTION' => 'A listing of the groups for your site. Provides management tools for editing and deleting groups.',
6465
'SUMMARY' => 'Group Summary',

app/sprinkles/admin/src/Controller/UserController.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,6 +1219,10 @@ public function updateInfo(Request $request, Response $response, $args)
12191219
return $response->withJson([], 400);
12201220
}
12211221

1222+
if (isset($data['group_id']) && $data['group_id'] == 0) {
1223+
$data['group_id'] = null;
1224+
}
1225+
12221226
// Begin transaction - DB will be rolled back if an exception occurs
12231227
Capsule::transaction(function () use ($data, $user, $currentUser) {
12241228
// Update the user and generate success messages

app/sprinkles/admin/templates/forms/user.html.twig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
<input type="text" class="form-control" name="theme" value="{{user.group.name}}" disabled>
2626
{% else %}
2727
<select id="input-group" class="form-control js-select2" name="group_id">
28+
<option value="0">{{translate('GROUP.NONE')}}</option>
29+
<option disabled="disabled">-----</option>
2830
{% for group in groups %}
2931
<option value="{{group.id}}" {% if (group.id == user.group_id) %}selected{% endif %}>{{group.name}}</option>
3032
{% endfor %}

app/sprinkles/admin/templates/pages/user.html.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@
9494
<i class="fa fa-fw fa-bolt fa-lg text-yellow" title="{{translate('UNACTIVATED')}}"></i>
9595
{% endif %}
9696
</div>
97-
<h4 class="text-muted text-center">{{user.user_name}}{% if 'group' not in fields.hidden %} • {{user.group.name}}{% endif %}</h4>
97+
<h4 class="text-muted text-center">{{user.user_name}}{% if 'group' not in fields.hidden and user.group.name is not null %} • {{user.group.name}}{% endif %}</h4>
9898

9999
{% if 'email' not in fields.hidden %}
100100
<hr>

0 commit comments

Comments
 (0)