Merge branch '1.1.x'
This commit is contained in:
@@ -117,7 +117,7 @@ public class EnvironmentController {
|
||||
public ResponseEntity<String> properties(@PathVariable String name,
|
||||
@PathVariable String profiles,
|
||||
@RequestParam(defaultValue = "true") boolean resolvePlaceholders)
|
||||
throws IOException {
|
||||
throws IOException {
|
||||
return labelledProperties(name, profiles, null, resolvePlaceholders);
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ public class EnvironmentController {
|
||||
public ResponseEntity<String> labelledProperties(@PathVariable String name,
|
||||
@PathVariable String profiles, @PathVariable String label,
|
||||
@RequestParam(defaultValue = "true") boolean resolvePlaceholders)
|
||||
throws IOException {
|
||||
throws IOException {
|
||||
validateProfiles(profiles);
|
||||
Environment environment = labelled(name, profiles, label);
|
||||
Map<String, Object> properties = convertToProperties(environment);
|
||||
@@ -141,7 +141,7 @@ public class EnvironmentController {
|
||||
public ResponseEntity<String> jsonProperties(@PathVariable String name,
|
||||
@PathVariable String profiles,
|
||||
@RequestParam(defaultValue = "true") boolean resolvePlaceholders)
|
||||
throws Exception {
|
||||
throws Exception {
|
||||
return labelledJsonProperties(name, profiles, null, resolvePlaceholders);
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ public class EnvironmentController {
|
||||
public ResponseEntity<String> labelledJsonProperties(@PathVariable String name,
|
||||
@PathVariable String profiles, @PathVariable String label,
|
||||
@RequestParam(defaultValue = "true") boolean resolvePlaceholders)
|
||||
throws Exception {
|
||||
throws Exception {
|
||||
validateProfiles(profiles);
|
||||
Environment environment = labelled(name, profiles, label);
|
||||
Map<String, Object> properties = convertToMap(environment);
|
||||
@@ -176,7 +176,7 @@ public class EnvironmentController {
|
||||
public ResponseEntity<String> yaml(@PathVariable String name,
|
||||
@PathVariable String profiles,
|
||||
@RequestParam(defaultValue = "true") boolean resolvePlaceholders)
|
||||
throws Exception {
|
||||
throws Exception {
|
||||
return labelledYaml(name, profiles, null, resolvePlaceholders);
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ public class EnvironmentController {
|
||||
public ResponseEntity<String> labelledYaml(@PathVariable String name,
|
||||
@PathVariable String profiles, @PathVariable String label,
|
||||
@RequestParam(defaultValue = "true") boolean resolvePlaceholders)
|
||||
throws Exception {
|
||||
throws Exception {
|
||||
validateProfiles(profiles);
|
||||
Environment environment = labelled(name, profiles, label);
|
||||
Map<String, Object> result = convertToMap(environment);
|
||||
@@ -310,10 +310,12 @@ public class EnvironmentController {
|
||||
|
||||
private Map<String, Object> convertToProperties(Environment profiles) {
|
||||
|
||||
// Map of unique keys containing full map of properties for each unique key
|
||||
Map<String, Map<String, Object>> map = new TreeMap<>();
|
||||
// Map of unique keys containing full map of properties for each unique
|
||||
// key
|
||||
Map<String, Map<String, Object>> map = new LinkedHashMap<>();
|
||||
List<PropertySource> sources = new ArrayList<>(profiles.getPropertySources());
|
||||
Collections.reverse(sources);
|
||||
Map<String, Object> combinedMap = new TreeMap<>();
|
||||
for (PropertySource source : sources) {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -323,26 +325,30 @@ public class EnvironmentController {
|
||||
if (!key.contains("[")) {
|
||||
|
||||
// Not an array, add unique key to the map
|
||||
map.put(key, value);
|
||||
combinedMap.put(key, value.get(key));
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
// An existing array might have already been added to the property map
|
||||
// of an unequal size
|
||||
// to the current array. Replace the array key in the current map
|
||||
map.put(key.substring(0, key.indexOf('[') - 1), value);
|
||||
// of an unequal size to the current array. Replace the array key in
|
||||
// the current map.
|
||||
key = key.substring(0, key.indexOf("["));
|
||||
Map<String, Object> filtered = new TreeMap<>();
|
||||
for (String index : value.keySet()) {
|
||||
if (index.startsWith(key + "[")) {
|
||||
filtered.put(index, value.get(index));
|
||||
}
|
||||
}
|
||||
map.put(key, filtered);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Combine all unique keys into a combined map
|
||||
Map<String, Object> combinedMap = new TreeMap<>();
|
||||
// Combine all unique keys for array values into the combined map
|
||||
for (Entry<String, Map<String, Object>> entry : map.entrySet()) {
|
||||
|
||||
combinedMap.putAll(entry.getValue());
|
||||
|
||||
}
|
||||
|
||||
postProcessProperties(combinedMap);
|
||||
|
||||
@@ -68,8 +68,7 @@ public class EnvironmentControllerTests {
|
||||
Map<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("a.b.c", "d");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("a:\n b:\n c: d\n", yaml);
|
||||
}
|
||||
@@ -79,14 +78,28 @@ public class EnvironmentControllerTests {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
map.put("a.b.c", "d");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
this.environment.addFirst(
|
||||
new PropertySource("two", Collections.singletonMap("a.b.c", "e")));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
this.environment.addFirst(new PropertySource("two", Collections.singletonMap("a.b.c", "e")));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("a:\n b:\n c: e\n", yaml);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propertyOverrideInYamlMultipleValues() throws Exception {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
map.put("A", "Y");
|
||||
map.put("S", 2);
|
||||
map.put("Y", 0);
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
map = new LinkedHashMap<String, Object>();
|
||||
map.put("A", "Z");
|
||||
map.put("S", 3);
|
||||
this.environment.addFirst(new PropertySource("two", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("A: Z\nS: 3\nY: 0\n", yaml);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void placeholdersResolvedInYaml() throws Exception {
|
||||
whenPlaceholders();
|
||||
@@ -100,8 +113,7 @@ public class EnvironmentControllerTests {
|
||||
map.put("a.b[0]", "c");
|
||||
map.put("a.b[1]", "d");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("a:\n b:\n - c\n - d\n", yaml);
|
||||
}
|
||||
@@ -121,8 +133,7 @@ public class EnvironmentControllerTests {
|
||||
twoMap.put("a.b[1]", "h");
|
||||
this.environment.addFirst(new PropertySource("two", twoMap));
|
||||
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "two"))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "two")).thenReturn(this.environment);
|
||||
Environment environment = this.controller.labelled("foo", "bar", "two");
|
||||
assertThat(environment, not(nullValue()));
|
||||
assertThat(environment.getName(), equalTo("foo"));
|
||||
@@ -131,11 +142,9 @@ public class EnvironmentControllerTests {
|
||||
assertThat(environment.getVersion(), nullValue());
|
||||
assertThat(environment.getPropertySources(), hasSize(2));
|
||||
assertThat(environment.getPropertySources().get(0).getName(), equalTo("two"));
|
||||
assertThat(environment.getPropertySources().get(0).getSource().entrySet(),
|
||||
hasSize(2));
|
||||
assertThat(environment.getPropertySources().get(0).getSource().entrySet(), hasSize(2));
|
||||
assertThat(environment.getPropertySources().get(1).getName(), equalTo("one"));
|
||||
assertThat(environment.getPropertySources().get(1).getSource().entrySet(),
|
||||
hasSize(3));
|
||||
assertThat(environment.getPropertySources().get(1).getSource().entrySet(), hasSize(3));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -153,8 +162,7 @@ public class EnvironmentControllerTests {
|
||||
twoMap.put("a.b[1]", "h");
|
||||
this.environment.addFirst(new PropertySource("two", twoMap));
|
||||
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
|
||||
// Result will not contain original, extra values from oneMap
|
||||
@@ -166,8 +174,7 @@ public class EnvironmentControllerTests {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
map.put("document", "blah");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("blah\n", yaml);
|
||||
}
|
||||
@@ -178,8 +185,7 @@ public class EnvironmentControllerTests {
|
||||
map.put("document[0]", "c");
|
||||
map.put("document[1]", "d");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("- c\n- d\n", yaml);
|
||||
}
|
||||
@@ -190,8 +196,7 @@ public class EnvironmentControllerTests {
|
||||
map.put("document[0].a", "c");
|
||||
map.put("document[1].a", "d");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("- a: c\n- a: d\n", yaml);
|
||||
}
|
||||
@@ -203,12 +208,10 @@ public class EnvironmentControllerTests {
|
||||
map.put("a.b[0].d", "e");
|
||||
map.put("a.b[1].c", "d");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertTrue("Wrong output: " + yaml,
|
||||
"a:\n b:\n - d: e\n c: d\n - c: d\n".equals(yaml)
|
||||
|| "a:\n b:\n - c: d\n d: e\n - c: d\n".equals(yaml));
|
||||
assertTrue("Wrong output: " + yaml, "a:\n b:\n - d: e\n c: d\n - c: d\n".equals(yaml)
|
||||
|| "a:\n b:\n - c: d\n d: e\n - c: d\n".equals(yaml));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -217,8 +220,7 @@ public class EnvironmentControllerTests {
|
||||
map.put("b[0].c", "d");
|
||||
map.put("b[1].c", "d");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("b:\n- c: d\n- c: d\n", yaml);
|
||||
}
|
||||
@@ -229,8 +231,7 @@ public class EnvironmentControllerTests {
|
||||
map.put("x.a.b[0].c", "d");
|
||||
map.put("x.a.b[1].c", "d");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
String yaml = this.controller.yaml("foo", "bar", false).getBody();
|
||||
assertEquals("x:\n a:\n b:\n - c: d\n - c: d\n", yaml);
|
||||
}
|
||||
@@ -253,116 +254,97 @@ public class EnvironmentControllerTests {
|
||||
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||
map.put("foo", "bar");
|
||||
this.environment.add(new PropertySource("one", map));
|
||||
this.environment.addFirst(
|
||||
new PropertySource("two", Collections.singletonMap("a.b.c", "${foo}")));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
this.environment.addFirst(new PropertySource("two", Collections.singletonMap("a.b.c", "${foo}")));
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForEnvironment() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo/bar"))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk());
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo/bar")).andExpect(MockMvcResultMatchers.status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForLabelledEnvironment() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "other"))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "other")).thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo/bar/other"))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk());
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo/bar/other")).andExpect(MockMvcResultMatchers.status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForYaml() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo-bar.yml"))
|
||||
.andExpect(
|
||||
MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN))
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN))
|
||||
.andExpect(MockMvcResultMatchers.content().string("{}\n"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForJson() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo-bar.json"))
|
||||
.andExpect(MockMvcResultMatchers.content()
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(MockMvcResultMatchers.content().string("{}"));
|
||||
;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForLabelledYaml() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "other"))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "other")).thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar.yml")).andExpect(
|
||||
MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN));
|
||||
mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar.yml"))
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForLabelledProperties() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "other"))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "other")).thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar.properties")).andExpect(
|
||||
MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN));
|
||||
mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar.properties"))
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForProperties() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo-bar.properties")).andExpect(
|
||||
MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN));
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo-bar.properties"))
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForLabelledYamlWithHyphen() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo-bar-foo2-bar2", "spam", "other"))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo-bar-foo2-bar2", "spam", "other")).thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar-foo2-bar2-spam.yml"))
|
||||
.andExpect(MockMvcResultMatchers.content()
|
||||
.contentType(MediaType.TEXT_PLAIN));
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.TEXT_PLAIN));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingforLabelledJsonProperties() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "other"))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", "other")).thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar.json")).andExpect(
|
||||
MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON));
|
||||
mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar.json"))
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingforJsonProperties() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo", "bar", null)).thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo-bar.json")).andExpect(
|
||||
MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON));
|
||||
mvc.perform(MockMvcRequestBuilders.get("/foo-bar.json"))
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mappingForLabelledJsonPropertiesWithHyphen() throws Exception {
|
||||
Mockito.when(this.repository.findOne("foo-bar-foo2-bar2", "spam", "other"))
|
||||
.thenReturn(this.environment);
|
||||
Mockito.when(this.repository.findOne("foo-bar-foo2-bar2", "spam", "other")).thenReturn(this.environment);
|
||||
MockMvc mvc = MockMvcBuilders.standaloneSetup(this.controller).build();
|
||||
mvc.perform(MockMvcRequestBuilders.get("/other/foo-bar-foo2-bar2-spam.json"))
|
||||
.andExpect(MockMvcResultMatchers.content()
|
||||
.contentType(MediaType.APPLICATION_JSON));
|
||||
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON));
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user