KEYCLOAK-17887 fix endpoint for creating or updating realm localization texts for a given locale (UnsupportedOperation was thrown because RealmAdapter tried to change unmodifiable map):
- fix RealmAdapter to create a new map instead of trying to change unmodifiable map - only provide POST endpoints for creating or updating the texts (to have the endpoints consistent with other Admin API endpoints) - add tests
This commit is contained in:
parent
d92bb7df65
commit
0a2f8f5b63
8 changed files with 57 additions and 18 deletions
|
@ -23,6 +23,7 @@ import java.util.Map;
|
|||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
|
@ -59,4 +60,9 @@ public interface RealmLocalizationResource {
|
|||
@PUT
|
||||
@Consumes(MediaType.TEXT_PLAIN)
|
||||
void saveRealmLocalizationText(@PathParam("locale") String locale, @PathParam("key") String key, String text);
|
||||
|
||||
@Path("{locale}")
|
||||
@POST
|
||||
@Consumes("application/json")
|
||||
void createOrUpdateRealmLocalizationTexts(@PathParam("locale") String locale, Map<String, String> localizationTexts);
|
||||
}
|
||||
|
|
|
@ -1698,9 +1698,9 @@ public class RealmAdapter implements CachedRealmModel {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void patchRealmLocalizationTexts(String locale, Map<String, String> localizationTexts) {
|
||||
public void createOrUpdateRealmLocalizationTexts(String locale, Map<String, String> localizationTexts) {
|
||||
getDelegateForUpdate();
|
||||
updated.patchRealmLocalizationTexts(locale, localizationTexts);
|
||||
updated.createOrUpdateRealmLocalizationTexts(locale, localizationTexts);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2173,11 +2173,13 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void patchRealmLocalizationTexts(String locale, Map<String, String> localizationTexts) {
|
||||
public void createOrUpdateRealmLocalizationTexts(String locale, Map<String, String> localizationTexts) {
|
||||
Map<String, RealmLocalizationTextsEntity> currentLocalizationTexts = realm.getRealmLocalizationTexts();
|
||||
if(currentLocalizationTexts.containsKey(locale)) {
|
||||
RealmLocalizationTextsEntity localizationTextsEntity = currentLocalizationTexts.get(locale);
|
||||
localizationTextsEntity.getTexts().putAll(localizationTexts);
|
||||
Map<String, String> updatedTexts = new HashMap<>(localizationTextsEntity.getTexts());
|
||||
updatedTexts.putAll(localizationTexts);
|
||||
localizationTextsEntity.setTexts(updatedTexts);
|
||||
|
||||
em.persist(localizationTextsEntity);
|
||||
}
|
||||
|
|
|
@ -1294,7 +1294,7 @@ public class MapRealmAdapter extends AbstractRealmModel<MapRealmEntity> implemen
|
|||
}
|
||||
|
||||
@Override
|
||||
public void patchRealmLocalizationTexts(String locale, Map<String, String> localizationTexts) {
|
||||
public void createOrUpdateRealmLocalizationTexts(String locale, Map<String, String> localizationTexts) {
|
||||
Map<String, Map<String, String>> realmLocalizationTexts = entity.getLocalizationTexts();
|
||||
|
||||
if (realmLocalizationTexts.containsKey(locale)) {
|
||||
|
|
|
@ -175,7 +175,7 @@ public class MapRealmProvider implements RealmProvider {
|
|||
if (! updateLocalizationText(realm, locale, key, text)) {
|
||||
Map<String, String> texts = new HashMap<>();
|
||||
texts.put(key, text);
|
||||
realm.patchRealmLocalizationTexts(locale, texts);
|
||||
realm.createOrUpdateRealmLocalizationTexts(locale, texts);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,7 +183,7 @@ public class MapRealmProvider implements RealmProvider {
|
|||
@Override
|
||||
public void saveLocalizationTexts(RealmModel realm, String locale, Map<String, String> localizationTexts) {
|
||||
if (locale == null || localizationTexts == null) return;
|
||||
realm.patchRealmLocalizationTexts(locale, localizationTexts);
|
||||
realm.createOrUpdateRealmLocalizationTexts(locale, localizationTexts);
|
||||
}
|
||||
|
||||
//TODO move the following method to adapter
|
||||
|
@ -192,7 +192,7 @@ public class MapRealmProvider implements RealmProvider {
|
|||
if (locale == null || key == null || text == null || (! realm.getRealmLocalizationTextsByLocale(locale).containsKey(key))) return false;
|
||||
Map<String, String> texts = new HashMap<>(realm.getRealmLocalizationTextsByLocale(locale));
|
||||
texts.replace(key, text);
|
||||
realm.patchRealmLocalizationTexts(locale, texts);
|
||||
realm.createOrUpdateRealmLocalizationTexts(locale, texts);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -210,7 +210,7 @@ public class MapRealmProvider implements RealmProvider {
|
|||
Map<String, String> texts = new HashMap<>(realm.getRealmLocalizationTextsByLocale(locale));
|
||||
texts.remove(key);
|
||||
realm.removeRealmLocalizationTexts(locale);
|
||||
realm.patchRealmLocalizationTexts(locale, texts);
|
||||
realm.createOrUpdateRealmLocalizationTexts(locale, texts);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -992,10 +992,11 @@ public interface RealmModel extends RoleContainerModel {
|
|||
void removeDefaultClientScope(ClientScopeModel clientScope);
|
||||
|
||||
/**
|
||||
* Patches the realm-specific localization texts. This method will not delete any text.
|
||||
* Creates or updates the realm-specific localization texts for the given locale.
|
||||
* This method will not delete any text.
|
||||
* It updates texts, which are already stored or create new ones if the key does not exist yet.
|
||||
*/
|
||||
void patchRealmLocalizationTexts(String locale, Map<String, String> localizationTexts);
|
||||
void createOrUpdateRealmLocalizationTexts(String locale, Map<String, String> localizationTexts);
|
||||
boolean removeRealmLocalizationTexts(String locale);
|
||||
Map<String, Map<String, String>> getRealmLocalizationTexts();
|
||||
Map<String, String> getRealmLocalizationTextsByLocale(String locale);
|
||||
|
|
|
@ -84,8 +84,8 @@ public class RealmLocalizationResource {
|
|||
@POST
|
||||
@Path("{locale}")
|
||||
@Consumes(MediaType.MULTIPART_FORM_DATA)
|
||||
public void patchRealmLocalizationTextsFromFile(@PathParam("locale") String locale, MultipartFormDataInput input)
|
||||
throws IOException {
|
||||
public void createOrUpdateRealmLocalizationTextsFromFile(@PathParam("locale") String locale,
|
||||
MultipartFormDataInput input) {
|
||||
this.auth.realm().requireManageRealm();
|
||||
|
||||
Map<String, List<InputPart>> formDataMap = input.getFormDataMap();
|
||||
|
@ -97,18 +97,19 @@ public class RealmLocalizationResource {
|
|||
TypeReference<HashMap<String, String>> typeRef = new TypeReference<HashMap<String, String>>() {
|
||||
};
|
||||
Map<String, String> rep = JsonSerialization.readValue(inputStream, typeRef);
|
||||
realm.patchRealmLocalizationTexts(locale, rep);
|
||||
realm.createOrUpdateRealmLocalizationTexts(locale, rep);
|
||||
} catch (IOException e) {
|
||||
throw new BadRequestException("Could not read file.");
|
||||
}
|
||||
}
|
||||
|
||||
@PATCH
|
||||
@POST
|
||||
@Path("{locale}")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public void patchRealmLocalizationTexts(@PathParam("locale") String locale, Map<String, String> loclizationTexts) {
|
||||
public void createOrUpdateRealmLocalizationTexts(@PathParam("locale") String locale,
|
||||
Map<String, String> localizationTexts) {
|
||||
this.auth.realm().requireManageRealm();
|
||||
realm.patchRealmLocalizationTexts(locale, loclizationTexts);
|
||||
realm.createOrUpdateRealmLocalizationTexts(locale, localizationTexts);
|
||||
}
|
||||
|
||||
@Path("{locale}")
|
||||
|
|
|
@ -17,15 +17,16 @@
|
|||
|
||||
package org.keycloak.testsuite.admin;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.RealmLocalizationResource;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -44,6 +45,7 @@ public class RealmLocalizationResourceTest extends AbstractAdminTest {
|
|||
|
||||
getCleanup().addLocalization("en");
|
||||
getCleanup().addLocalization("de");
|
||||
getCleanup().addLocalization("es");
|
||||
|
||||
resource = adminClient.realm(REALM_NAME).localization();
|
||||
}
|
||||
|
@ -127,4 +129,31 @@ public class RealmLocalizationResourceTest extends AbstractAdminTest {
|
|||
|
||||
assertThat(localizations, CoreMatchers.hasItems("de"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createOrUpdateRealmLocalizationWhenLocaleDoesNotYetExist() {
|
||||
final Map<String, String> newLocalizationTexts = new HashMap<>();
|
||||
newLocalizationTexts.put("key-a", "text-a_es");
|
||||
newLocalizationTexts.put("key-b", "text-b_es");
|
||||
|
||||
resource.createOrUpdateRealmLocalizationTexts("es", newLocalizationTexts);
|
||||
|
||||
final Map<String, String> persistedLocalizationTexts = resource.getRealmLocalizationTexts("es");
|
||||
assertEquals(newLocalizationTexts, persistedLocalizationTexts);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createOrUpdateRealmLocalizationWhenLocaleAlreadyExists() {
|
||||
final Map<String, String> newLocalizationTexts = new HashMap<>();
|
||||
newLocalizationTexts.put("key-b", "text-b_changed_en");
|
||||
newLocalizationTexts.put("key-c", "text-c_en");
|
||||
|
||||
resource.createOrUpdateRealmLocalizationTexts("en", newLocalizationTexts);
|
||||
|
||||
final Map<String, String> expectedLocalizationTexts = new HashMap<>();
|
||||
expectedLocalizationTexts.put("key-a", "text-a_en");
|
||||
expectedLocalizationTexts.putAll(newLocalizationTexts);
|
||||
final Map<String, String> persistedLocalizationTexts = resource.getRealmLocalizationTexts("en");
|
||||
assertEquals(expectedLocalizationTexts, persistedLocalizationTexts);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue