Commit f29db93f authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Handled is leaf field also in UI

parent d66e51ab
......@@ -28,5 +28,6 @@
"hasPreviousPages": false,
"hasFollowingPages": false
},
"permission": "ADMIN"
"permission": "ADMIN",
"leaf": false
}
......@@ -2,7 +2,7 @@ const BASE_API_URL = process.env.VUE_APP_API_BASE_URL;
function apiRequest(url, options) {
loading(true);
return new Promise((resolve, reject) => {
return new Promise((resolve) => {
fetch(url, options)
.then(response => {
loading(false);
......@@ -123,7 +123,7 @@ export default {
}
});
},
addGroup(newGroupName, input) {
addGroup(newGroupName, leaf, input) {
let url = BASE_API_URL + 'group';
return apiRequest(url, {
method: 'POST',
......@@ -138,11 +138,12 @@ export default {
parentGroupId: input.selectedGroupId,
paginatorPageSize: input.paginatorPageSize,
paginatorPage: input.paginatorPage,
searchFilter: input.searchFilter
searchFilter: input.searchFilter,
leaf: leaf
})
});
},
renameGroup(groupId, newGroupName, input) {
renameGroup(groupId, newGroupName, leaf, input) {
let url = BASE_API_URL + 'group/' + groupId;
return apiRequest(url, {
method: 'PUT',
......@@ -154,6 +155,7 @@ export default {
},
body: JSON.stringify({
newGroupName: newGroupName,
leaf: leaf,
paginatorPageSize: input.paginatorPageSize,
paginatorPage: input.paginatorPage,
searchFilter: input.searchFilter
......
......@@ -43,7 +43,7 @@ export default {
changeBreadcrumb: function(groupId) {
this.input.selectedGroupId = groupId;
this.input.searchFilter = null;
if (this.input.selectedTab === 'groups') {
if (this.input.tabIndex === 0) {
client.fetchGroupsTab(this.input)
.then(model => {
this.$store.commit('updateGroups', model);
......
<template>
<b-tab title="Groups" active>
<b-tab title="Groups" :title-link-class="{ 'd-none': model.leaf }">
<b-row>
<b-col xs="12">
<b-form-input placeholder="Search group" v-model="input.searchFilter" v-on:input="filterGroups"></b-form-input>
......
......@@ -47,48 +47,33 @@ export default {
computed: mapState({
model: state => state.model,
input: state => state.input,
showAddMemberBtn: state => state.model.permission === 'ADMIN' && state.input.selectedTab === 'members',
showAddCollaboratorBtn: state => state.model.permission === 'MANAGE_MEMBERS' && state.input.selectedTab === 'members',
showAddGroupBtn: state => state.model.permission === 'ADMIN' && state.input.selectedTab === 'groups',
showAddPermissionBtn: state => state.model.permission === 'ADMIN' && state.input.selectedTab === 'permissions'
showAddMemberBtn: state => state.model.permission === 'ADMIN' && state.input.tabIndex === 1,
showAddCollaboratorBtn: state => state.model.permission === 'MANAGE_MEMBERS' && state.input.tabIndex === 1,
showAddGroupBtn: state => state.model.permission === 'ADMIN' && state.input.tabIndex === 0,
showAddPermissionBtn: state => state.model.permission === 'ADMIN' && state.input.tabIndex === 2
}),
methods: {
tabChanged: function(tabIndex) {
let tab;
switch (tabIndex) {
case 0:
tab = 'groups';
client.fetchGroupsTab(this.input)
.then(model => {
this.$store.commit('updateGroups', model);
});
break;
case 1:
tab = 'members';
client.fetchMembersPanel(this.input)
.then(panel => {
this.$store.commit('updateMembersPanel', panel);
});
break;
case 2:
tab = 'permissions';
client.fetchPermissionsPanel(this.input)
.then(panel => {
this.$store.commit('updatePermissionsPanel', panel);
});
break;
}
if (this.input.selectedTab !== tab) {
this.input.selectedTab = tab;
switch (this.input.selectedTab) {
case 'groups':
client.fetchGroupsTab(this.input)
.then(model => {
this.$store.commit('updateGroups', model);
});
break;
case 'members':
client.fetchMembersPanel(this.input)
.then(panel => {
this.$store.commit('updateMembersPanel', panel);
});
break;
case 'permissions':
client.fetchPermissionsPanel(this.input)
.then(panel => {
this.$store.commit('updatePermissionsPanel', panel);
});
break;
}
}
},
openAddGroupModal: function() {
this.$bvModal.show('add-group-modal');
......
......@@ -5,6 +5,7 @@
<b-form-input v-model="newGroupName" id="new-group-name-input" ref="newGroupNameInput" class="w-75" aria-describedby="new-group-name-input-feedback" :state="newGroupNameState" v-on:input="resetError" @keydown.native.enter="addGroup">
</b-form-input>
<b-form-invalid-feedback id="new-group-name-input-feedback">{{newGroupNameError}}</b-form-invalid-feedback>
<b-form-checkbox class="mt-3 ml-3" v-model="leaf">is leaf</b-form-checkbox>
</b-form>
</b-modal>
</template>
......@@ -24,7 +25,8 @@ export default {
data: function() {
return {
newGroupName: null,
newGroupNameError: null
newGroupNameError: null,
leaf: false
};
},
methods: {
......@@ -45,7 +47,7 @@ export default {
if (!this.newGroupName) {
this.newGroupNameError = "Group name is required";
} else {
client.addGroup(this.newGroupName, this.$store.state.input)
client.addGroup(this.newGroupName, this.leaf, this.$store.state.input)
.then(res => {
if (res.status === 400) {
this.newGroupNameError = res.message;
......
......@@ -5,6 +5,7 @@
<b-form-input v-model="newGroupName" id="new-group-name-input" class="w-75" aria-describedby="new-group-name-input-feedback" :state="newGroupNameState" v-on:input="resetError">
</b-form-input>
<b-form-invalid-feedback id="new-group-name-input-feedback">{{newGroupNameError}}</b-form-invalid-feedback>
<b-form-checkbox class="mt-3 ml-3" v-model="leaf">is leaf</b-form-checkbox>
</b-form>
</b-modal>
</template>
......@@ -26,7 +27,8 @@ export default {
groupId: null,
oldGroupName: null,
newGroupName: null,
newGroupNameError: null
newGroupNameError: null,
leaf: false
};
},
methods: {
......@@ -36,6 +38,7 @@ export default {
openRenameGroupModal: function(group) {
this.newGroupName = group.groupName;
this.groupId = group.groupId;
this.leaf = group.leaf;
this.$bvModal.show('rename-group-modal');
},
renameGroup: function(event) {
......@@ -53,7 +56,7 @@ export default {
}
let parent = this.$store.getters.selectedGroupId;
client.renameGroup(this.groupId, this.newGroupName, this.$store.state.input)
client.renameGroup(this.groupId, this.newGroupName, this.leaf, this.$store.state.input)
.then(res => {
if (res.status === 400) {
this.newGroupNameError = res.message;
......
......@@ -15,6 +15,7 @@ export default new Vuex.Store({
permissionsPanel: null,
membersPanel: null,
permission: null,
leaf: false,
user: null,
genericSearchResults: [],
userSearchResults: {
......@@ -28,7 +29,6 @@ export default new Vuex.Store({
selectedGroupId: 'ROOT',
paginatorPageSize: 20,
paginatorPage: 1,
selectedTab: 'groups',
tabIndex: 0,
searchFilter: '',
genericSearch: {
......@@ -54,11 +54,11 @@ export default new Vuex.Store({
client.fetchGroupsTab(input)
.then(model => {
this.commit('updateGroups', model);
if (model.groupsPanel.items.length > 0) {
this.commit('setTabIndex', 0);
} else {
if (model.leaf) {
// If there are no subgroups show the members panel
this.commit('setTabIndex', 1);
} else {
this.commit('setTabIndex', 0);
}
this.commit('showMainPage');
});
......@@ -67,6 +67,7 @@ export default new Vuex.Store({
this.state.model.breadcrumbs = model.breadcrumbs;
this.state.model.groupsPanel = model.groupsPanel;
this.state.model.permission = model.permission;
this.state.model.leaf = model.leaf;
},
updateGroupsPanel(state, groupsPanel) {
this.state.model.groupsPanel = groupsPanel;
......
......@@ -55,7 +55,7 @@ public class BasicAuthWebServiceController {
if (optGroup.isPresent()) {
group = optGroup.get();
} else {
group = groupsService.addGroup(group, name);
group = groupsService.addGroup(group, name, false);
}
}
......
......@@ -67,7 +67,7 @@ public class GroupsController {
throw new UnauthorizedException("Missing admin permission");
}
groupsService.addGroup(parent, request.getNewGroupName());
groupsService.addGroup(parent, request.getNewGroupName(), request.isLeaf());
PaginatedData<GroupNode> groupsPanel = getGroupsPanel(parent, request);
......@@ -83,7 +83,7 @@ public class GroupsController {
throw new UnauthorizedException("Missing admin permission");
}
GroupEntity renamedGroup = groupsService.renameGroup(group, request.getNewGroupName());
GroupEntity renamedGroup = groupsService.renameGroup(group, request.getNewGroupName(), request.isLeaf());
GroupEntity parent = groupsService.getGroupByPath(renamedGroup.getParentPath());
......
......@@ -39,6 +39,8 @@ public class GroupsTabResponseBuilder {
response.setGroupsPanel(groupsListBuilder.listSubGroups(group, request, session.getUserId()));
response.setLeaf(group.isLeaf());
return response;
}
}
......@@ -3,6 +3,7 @@ package it.inaf.ia2.gms.model;
public class Identity {
private IdentityType type;
private String typedId;
private String email;
private String name;
private String surname;
......@@ -16,6 +17,14 @@ public class Identity {
this.type = type;
}
public String getTypedId() {
return typedId;
}
public void setTypedId(String typedId) {
this.typedId = typedId;
}
public String getEmail() {
return email;
}
......
......@@ -46,8 +46,13 @@ public class RapUser {
}
// Adding types
Set<String> types = identities.stream().map(i -> i.getType().getValue()).collect(Collectors.toSet());
displayName += String.format(" (%s)", String.join(",", types));
Set<String> types = identities.stream().map(i -> {
if (i.getType() == IdentityType.EDU_GAIN && i.getTypedId().endsWith("@ia2.inaf.it")) {
return "IA2";
}
return i.getType().getValue();
}).collect(Collectors.toSet());
displayName += String.format(" (%s)", String.join(", ", types));
return displayName;
}
......
......@@ -9,6 +9,8 @@ public class RenameGroupRequest extends PaginatedModelRequest implements SearchF
@Size(min = 1)
private String newGroupName;
private boolean leaf;
private String searchFilter;
public String getNewGroupName() {
......@@ -28,4 +30,12 @@ public class RenameGroupRequest extends PaginatedModelRequest implements SearchF
public void setSearchFilter(String searchFilter) {
this.searchFilter = searchFilter;
}
public boolean isLeaf() {
return leaf;
}
public void setLeaf(boolean leaf) {
this.leaf = leaf;
}
}
......@@ -12,6 +12,8 @@ public class GroupsTabResponse {
// current group permissions
private Permission permission;
private boolean leaf;
public List<GroupBreadcrumb> getBreadcrumbs() {
return breadcrumbs;
}
......@@ -35,4 +37,12 @@ public class GroupsTabResponse {
public void setPermission(Permission permission) {
this.permission = permission;
}
public boolean isLeaf() {
return leaf;
}
public void setLeaf(boolean leaf) {
this.leaf = leaf;
}
}
......@@ -30,13 +30,14 @@ public class GroupsDAO {
public GroupEntity createGroup(GroupEntity group) {
String sql = "INSERT INTO gms_group (id, name, path) VALUES (?, ?, ?)";
String sql = "INSERT INTO gms_group (id, name, path, is_leaf) VALUES (?, ?, ?, ?)";
jdbcTemplate.update(conn -> {
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, group.getId());
ps.setString(2, group.getName());
ps.setObject(3, group.getPath(), Types.OTHER);
ps.setBoolean(4, group.isLeaf());
return ps;
});
......@@ -45,13 +46,14 @@ public class GroupsDAO {
public GroupEntity updateGroup(GroupEntity group) {
String sql = "UPDATE gms_group SET name = ?, path = ? WHERE id = ?";
String sql = "UPDATE gms_group SET name = ?, path = ?, is_leaf = ? WHERE id = ?";
jdbcTemplate.update(conn -> {
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, group.getName());
ps.setObject(2, group.getPath(), Types.OTHER);
ps.setString(3, group.getId());
ps.setBoolean(3, group.isLeaf());
ps.setString(4, group.getId());
return ps;
});
......
......@@ -16,13 +16,13 @@ import java.util.stream.Collectors;
@Service
public class GroupsService {
public static final String ROOT = "ROOT";
private final GroupsDAO groupsDAO;
private final PermissionsDAO permissionsDAO;
private final MembershipsDAO membershipsDAO;
@Autowired
public GroupsService(GroupsDAO groupsDAO,
PermissionsDAO permissionsDAO, MembershipsDAO membershipsDAO) {
......@@ -31,7 +31,7 @@ public class GroupsService {
this.membershipsDAO = membershipsDAO;
createRootIfNecessary();
}
private void createRootIfNecessary() {
if (groupsDAO.count() == 0) {
GroupEntity root = new GroupEntity();
......@@ -41,88 +41,90 @@ public class GroupsService {
groupsDAO.createGroup(root);
}
}
public GroupEntity addGroup(GroupEntity parent, String groupName) {
public GroupEntity addGroup(GroupEntity parent, String groupName, boolean leaf) {
if (groupsDAO.getDirectSubGroups(parent.getPath()).stream()
.anyMatch(g -> g.getName().equals(groupName))) {
throw new BadRequestException("There is already a group named " + groupName);
}
String newGroupId = UUID.randomUUID().toString().replaceAll("-", "");
String path = parent.getPath();
if (!path.isEmpty()) {
path += ".";
}
path += newGroupId;
GroupEntity group = new GroupEntity();
group.setId(newGroupId);
group.setName(groupName);
group.setPath(path);
group.setLeaf(leaf);
groupsDAO.createGroup(group);
return group;
}
public GroupEntity renameGroup(GroupEntity group, String newGroupName) {
public GroupEntity renameGroup(GroupEntity group, String newGroupName, boolean leaf) {
if (groupsDAO.getDirectSubGroups(group.getPath()).stream()
.anyMatch(g -> g.getName().equals(newGroupName))) {
throw new BadRequestException("There is already a group named " + newGroupName);
}
group.setName(newGroupName);
group.setLeaf(leaf);
return groupsDAO.updateGroup(group);
}
public GroupEntity deleteGroup(GroupEntity group) {
if (ROOT.equals(group.getId())) {
throw new UnauthorizedException("It is not possible to remove the ROOT");
}
String parentPath = group.getParentPath();
GroupEntity parent = groupsDAO.findGroupByPath(parentPath)
.orElseThrow(() -> new BadRequestException("No group found at path " + parentPath));
List<GroupEntity> groupsToDelete = groupsDAO.getAllChildren(group.getPath());
groupsToDelete.add(group);
List<String> groupsToDeleteIds = groupsToDelete.stream()
.map(g -> g.getId()).collect(Collectors.toList());
membershipsDAO.deleteAllGroupsMembership(groupsToDeleteIds);
permissionsDAO.deleteAllGroupsPermissions(groupsToDeleteIds);
for (String groupId : groupsToDeleteIds) {
groupsDAO.deleteGroupById(groupId);
}
return parent;
}
public GroupEntity getRoot() {
return getGroupById(ROOT);
}
public GroupEntity getGroupById(String groupId) {
return groupsDAO.findGroupById(groupId)
.orElseThrow(() -> new BadRequestException("Group " + groupId + " not found"));
}
public GroupEntity getGroupByPath(String path) {
return groupsDAO.findGroupByPath(path)
.orElseThrow(() -> new BadRequestException("Group not found at path " + path));
}
public List<GroupBreadcrumb> getBreadcrumbs(String path) {
return groupsDAO.getBreadcrumbs(path);
}
public Optional<GroupEntity> findGroupByParentAndName(GroupEntity parent, String childName) {
return groupsDAO.findGroupByParentAndName(parent.getPath(), childName);
}
......@@ -137,7 +139,7 @@ public class GroupsService {
// after retrieving this list it is necessary to match for the correct
// group
List<GroupEntity> groups = groupsDAO.findGroupsByNames(names);
String parentPath = "";
GroupEntity group = null;
for (String name : names) {
......@@ -148,10 +150,10 @@ public class GroupsService {
parentPath = group.getPath();
}
}
return Optional.ofNullable(group);
}
private GroupEntity findGroup(List<GroupEntity> groups, String parentPath, String groupName) {
for (GroupEntity group : groups) {
if (parentPath.equals(group.getParentPath()) && groupName.equals(group.getName())) {
......@@ -160,7 +162,7 @@ public class GroupsService {
}
return null;
}
public List<GroupEntity> searchGroups(String searchText) {
return groupsDAO.searchGroups(searchText);
}
......
......@@ -19,6 +19,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.anyBoolean;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import static org.mockito.Mockito.times;
......@@ -74,7 +75,7 @@ public class BasicAuthWebServiceControllerTest {
when(groupsService.getRoot()).thenReturn(root);
when(groupsService.findGroupByParentAndName(eq(root), eq("LBT"))).thenReturn(Optional.of(lbt));
when(groupsService.addGroup(eq(lbt), eq("INAF"))).thenReturn(inaf);
when(groupsService.addGroup(eq(lbt), eq("INAF"), anyBoolean())).thenReturn(inaf);
List<String> names = Arrays.asList("LBT", "INAF");
......
......@@ -47,12 +47,12 @@ public class NestedGroupsIntegrationTest {
// Setup groups
GroupEntity root = groupsService.getRoot();
GroupEntity lbt = groupsService.addGroup(root, "LBT");
GroupEntity tng = groupsService.addGroup(root, "TNG");
GroupEntity radio = groupsService.addGroup(root, "Radio");
GroupEntity lbtInaf = groupsService.addGroup(lbt, "INAF");