reg/account custom attributes

This commit is contained in:
Bill Burke 2015-03-04 17:25:50 -05:00
parent 5a37754b62
commit 33520e9fec
12 changed files with 196 additions and 3 deletions

View file

@ -3,6 +3,8 @@ package org.keycloak.account.freemarker.model;
import org.keycloak.models.UserModel;
import javax.ws.rs.core.MultivaluedMap;
import java.util.HashMap;
import java.util.Map;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@ -11,10 +13,20 @@ public class AccountBean {
private final UserModel user;
private final MultivaluedMap<String, String> profileFormData;
private final Map<String, String> attributes = new HashMap<>();
public AccountBean(UserModel user, MultivaluedMap<String, String> profileFormData) {
this.user = user;
this.profileFormData = profileFormData;
attributes.putAll(user.getAttributes());
if (profileFormData != null) {
for (String key : profileFormData.keySet()) {
if (key.startsWith("user.attributes.")) {
String attribute = key.substring("user.attributes.".length());
attributes.put(attribute, profileFormData.getFirst(key));
}
}
}
}
public String getFirstName() {
@ -33,4 +45,8 @@ public class AccountBean {
return profileFormData != null ? profileFormData.getFirst("email") :user.getEmail();
}
public Map<String, String> getAttributes() {
return attributes;
}
}

View file

@ -55,6 +55,52 @@
</div>
</div>
<div class="form-group">
<div class="col-sm-2 col-md-2">
<label for="user.attributes.street" class="control-label">${rb.street}</label>
</div>
<div class="col-sm-10 col-md-10">
<input type="text" class="form-control" id="user.attributes.street" name="user.attributes.street" value="${(account.attributes.street!'')?html}"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-2 col-md-2">
<label for="user.attributes.locality" class="control-label">${rb.locality}</label>
</div>
<div class="col-sm-10 col-md-10">
<input type="text" class="form-control" id="user.attributes.locality" name="user.attributes.locality" value="${(account.attributes.locality!'')?html}"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-2 col-md-2">
<label for="user.attributes.region" class="control-label">${rb.region}</label>
</div>
<div class="col-sm-10 col-md-10">
<input type="text" class="form-control" id="user.attributes.region" name="user.attributes.region" value="${(account.attributes.region!'')?html}"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-2 col-md-2">
<label for="user.attributes.postal_code" class="control-label">${rb.postal_code}</label>
</div>
<div class="col-sm-10 col-md-10">
<input type="text" class="form-control" id="user.attributes.postal_code" name="user.attributes.postal_code" value="${(account.attributes.postal_code!'')?html}"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-2 col-md-2">
<label for="user.attributes.country" class="control-label">${rb.country}</label>
</div>
<div class="col-sm-10 col-md-10">
<input type="text" class="form-control" id="user.attributes.country" name="user.attributes.country" value="${(account.attributes.country!'')?html}"/>
</div>
</div>
<div class="form-group">
<div id="kc-form-buttons" class="col-md-offset-2 col-md-10 submit">
<div class="">

View file

@ -8,6 +8,11 @@ passwordConfirm=Confirmation
passwordNew=New Password
successHeader=Success!
username=Username
street=Street
locality=City or Locality
region=State, Province, or Region
postal_code=Zip or Postal code
country=Country
missingFirstName=Please specify first name
invalidEmail=Invalid email address

View file

@ -179,12 +179,15 @@ module.controller('UserListCtrl', function($scope, realm, User) {
module.controller('UserDetailCtrl', function($scope, realm, user, User, UserFederationInstances, $location, Dialog, Notifications) {
$scope.realm = realm;
$scope.user = angular.copy(user);
$scope.create = !user.username;
if ($scope.create) {
$scope.user.enabled = true;
$scope.user = { enabled: true, attributes: {} }
} else {
if (!user.attributes) {
user.attributes = {}
}
$scope.user = angular.copy(user);
if(user.federationLink) {
console.log("federationLink is not null");
UserFederationInstances.get({realm : realm.realm, instance: user.federationLink}, function(link) {

View file

@ -0,0 +1,38 @@
<fieldset>
<legend collapsed><span class="text">Contact Information</span> <span tooltip-placement="right" tooltip="Expand this section to configure user's contact information." class="fa fa-info-circle"></span></legend>
<div class="form-group clearfix block">
<label class="col-sm-2 control-label" for="street">Street</label>
<div class="col-sm-6">
<input ng-model="user.attributes.street" class="form-control" type="text" name="street" id="street" />
</div>
<span tooltip-placement="right" tooltip="Street address." class="fa fa-info-circle"></span>
</div>
<div class="form-group clearfix block">
<label class="col-sm-2 control-label" for="locality">City or Locality</label>
<div class="col-sm-6">
<input ng-model="user.attributes.locality" class="form-control" type="text" name="locality" id="locality" />
</div>
<span tooltip-placement="right" tooltip="City or locality." class="fa fa-info-circle"></span>
</div>
<div class="form-group clearfix block">
<label class="col-sm-2 control-label" for="region">State, Province, or Region</label>
<div class="col-sm-6">
<input ng-model="user.attributes.region" class="form-control" type="text" name="region" id="region" />
</div>
<span tooltip-placement="right" tooltip="State, province, prefecture, or region." class="fa fa-info-circle"></span>
</div>
<div class="form-group clearfix block">
<label class="col-sm-2 control-label" for="postal_code">Zip or Postal code</label>
<div class="col-sm-6">
<input ng-model="user.attributes.postal_code" class="form-control" type="text" name="postal_code" id="postal_code" />
</div>
<span tooltip-placement="right" tooltip="Zip code or postal code." class="fa fa-info-circle"></span>
</div>
<div class="form-group clearfix block">
<label class="col-sm-2 control-label" for="country">Country</label>
<div class="col-sm-6">
<input ng-model="user.attributes.country" class="form-control" type="text" name="country" id="country" />
</div>
<span tooltip-placement="right" tooltip="Country name." class="fa fa-info-circle"></span>
</div>
</fieldset>

View file

@ -101,6 +101,7 @@
<span tooltip-placement="right" tooltip="Require an action when the user logs in. 'Verify email' sends an email to the user to verify their email address. 'Update profile' requires user to enter in new personal information. 'Update password' requires user to enter in a new password. 'Configure TOTP' requires setup of a mobile password generator." class="fa fa-info-circle"></span>
</div>
</fieldset>
<div data-ng-include data-src="resourceUrl + '/partials/user-attribute-entry.html'"></div>
<div class="pull-right form-actions" data-ng-show="create && access.manageUsers">
<button kc-cancel data-ng-click="cancel()">Cancel</button>
<button kc-save data-ng-show="changed">Save</button>

View file

@ -6,6 +6,11 @@ register=Register
registerWith=Register with
allRequired=All fields are required
alreadyHaveAccount=Already have an account?
street=Street
locality=City or Locality
region=State, Province, or Region
postal_code=Zip or Postal code
country=Country
poweredByKeycloak=Powered by Keycloak

View file

@ -60,6 +60,53 @@
</div>
</div>
<div class="form-group">
<div class="${properties.kcLabelWrapperClass!}">
<label for="user.attributes.street" class="${properties.kcLabelClass!}">${rb.street}</label>
</div>
<div class="col-sm-10 col-md-10">
<input type="text" class="${properties.kcInputClass!}" id="user.attributes.street" name="user.attributes.street"/>
</div>
</div>
<div class="form-group">
<div class="${properties.kcLabelWrapperClass!}">
<label for="user.attributes.locality" class="${properties.kcLabelClass!}">${rb.locality}</label>
</div>
<div class="col-sm-10 col-md-10">
<input type="text" class="${properties.kcInputClass!}" id="user.attributes.locality" name="user.attributes.locality"/>
</div>
</div>
<div class="form-group">
<div class="${properties.kcLabelWrapperClass!}">
<label for="user.attributes.region" class="${properties.kcLabelClass!}">${rb.region}</label>
</div>
<div class="col-sm-10 col-md-10">
<input type="text" class="${properties.kcInputClass!}" id="user.attributes.region" name="user.attributes.region"/>
</div>
</div>
<div class="form-group">
<div class="${properties.kcLabelWrapperClass!}">
<label for="user.attributes.postal_code" class="${properties.kcLabelClass!}">${rb.postal_code}</label>
</div>
<div class="col-sm-10 col-md-10">
<input type="text" class="${properties.kcInputClass!}" id="user.attributes.postal_code" name="user.attributes.postal_code"/>
</div>
</div>
<div class="form-group">
<div class="${properties.kcLabelWrapperClass!}">
<label for="user.attributes.country" class="${properties.kcLabelClass!}">${rb.country}</label>
</div>
<div class="col-sm-10 col-md-10">
<input type="text" class="${properties.kcInputClass!}" id="user.attributes.country" name="user.attributes.country"/>
</div>
</div>
<div class="${properties.kcFormGroupClass!}">
<div id="kc-form-options" class="${properties.kcFormOptionsClass!}">
<div class="${properties.kcFormOptionsWrapperClass!}">

View file

@ -432,6 +432,8 @@ public class AccountService {
user.setEmail(formData.getFirst("email"));
AttributeFormDataProcessor.process(formData, realm, user);
event.event(EventType.UPDATE_PROFILE).client(auth.getClient()).user(auth.getUser()).success();
if (emailChanged) {

View file

@ -0,0 +1,28 @@
package org.keycloak.services.resources;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import javax.ws.rs.core.MultivaluedMap;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class AttributeFormDataProcessor {
/**
* Looks for "user.attributes." keys in the form data and sets the appropriate UserModel.attribute from it.
*
* @param formData
* @param realm
* @param user
*/
public static void process(MultivaluedMap<String, String> formData, RealmModel realm, UserModel user) {
for (String key : formData.keySet()) {
if (!key.startsWith("user.attributes.")) continue;
String attribute = key.substring("user.attributes.".length());
user.setAttribute(attribute, formData.getFirst(key));
}
}
}

View file

@ -507,6 +507,8 @@ public class LoginActionsService {
}
}
AttributeFormDataProcessor.process(formData, realm, user);
event.user(user).success();
event.reset();

View file

@ -157,7 +157,7 @@ public class AccountTest {
});
}
@Test @Ignore
//@Test @Ignore
public void runit() throws Exception {
Thread.sleep(10000000);
}