Skip to content

Commit

Permalink
SHIBUI-1848
Browse files Browse the repository at this point in the history
Basic controller and supporting items for CRUD operations around user
groups
  • Loading branch information
chasegawa committed Jun 23, 2021
1 parent 21e875f commit c111333
Show file tree
Hide file tree
Showing 6 changed files with 354 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package edu.internet2.tier.shibboleth.admin.ui.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import edu.internet2.tier.shibboleth.admin.ui.domain.Group;
import edu.internet2.tier.shibboleth.admin.ui.service.IGroupService;

@Controller
@RequestMapping(value = "/api/groups")
public class GroupController {
@Autowired
private IGroupService groupService;

@PostMapping
@Transactional
public ResponseEntity<?> create(@RequestBody Group group) {
// If already defined, we can't create a new one, nor will this call update the definition
Group g = groupService.find(group.getResourceId());

if (g != null) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ServletUriComponentsBuilder.fromCurrentServletMapping().path("/api/groups").build().toUri());

return ResponseEntity.status(HttpStatus.METHOD_NOT_ALLOWED).headers(headers)
.body(new ErrorResponse(String.valueOf(HttpStatus.METHOD_NOT_ALLOWED.value()),
String.format("The group with resource id: [%s] and name: [%s] already exists.",
group.getResourceId(), group.getName())));
}

Group result = groupService.createOrUpdateGroup(g);
return ResponseEntity.status(HttpStatus.CREATED).body(result);
}

@PutMapping
@Transactional
public ResponseEntity<?> update(@RequestBody Group group) {
Group g = groupService.find(group.getResourceId());

if (g == null) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ServletUriComponentsBuilder.fromCurrentServletMapping().path("/api/groups").build().toUri());

return ResponseEntity.status(HttpStatus.NOT_FOUND).headers(headers)
.body(new ErrorResponse(String.valueOf(HttpStatus.NOT_FOUND.value()),
String.format("Unable to find group with resource id: [%s] and name: [%s]",
group.getResourceId(), group.getName())));
}

Group result = groupService.createOrUpdateGroup(g);
return ResponseEntity.ok(result);
}

@GetMapping
@Transactional(readOnly = true)
public ResponseEntity<?> getAll() {
return ResponseEntity.ok(groupService.findAll());
}

@GetMapping("/{resourceId}")
@Transactional(readOnly = true)
public ResponseEntity<?> getOne(@PathVariable String resourceId) {
Group g = groupService.find(resourceId);

if (g == null) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ServletUriComponentsBuilder.fromCurrentServletMapping().path("/api/groups").build().toUri());

return ResponseEntity.status(HttpStatus.NOT_FOUND).headers(headers)
.body(new ErrorResponse(String.valueOf(HttpStatus.NOT_FOUND.value()),
String.format("Unable to find group with resource id: [%s]", resourceId)));
}
return ResponseEntity.ok(g);
}

@DeleteMapping("/{resourceId}")
@Transactional
public ResponseEntity<?> delete(@PathVariable String resourceId) {
Group g = groupService.find(resourceId);

if (g == null) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ServletUriComponentsBuilder.fromCurrentServletMapping().path("/api/groups").build().toUri());

return ResponseEntity.status(HttpStatus.NOT_FOUND).headers(headers)
.body(new ErrorResponse(String.valueOf(HttpStatus.NOT_FOUND.value()),
String.format("Unable to find group with resource id: [%s]", resourceId)));
}
try {
groupService.deleteDefinition(g);
}
catch (Exception e) {
HttpHeaders headers = new HttpHeaders();
headers.setLocation(ServletUriComponentsBuilder.fromCurrentServletMapping().path("/api/groups").build().toUri());

return ResponseEntity.status(HttpStatus.CONFLICT).headers(headers)
.body(new ErrorResponse(String.valueOf(HttpStatus.CONFLICT.value()), String.format(
"Unable to delete group with resource id: [%s] - remove all users from group",
resourceId)));
}
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package edu.internet2.tier.shibboleth.admin.ui.domain;

import java.util.UUID;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;

import org.hibernate.envers.Audited;

import lombok.Data;

@Entity(name = "user_groups")
@Audited
@Data
public class Group {
@Column(name = "group_description", nullable = true)
String description;

@Column(nullable = false)
String name;

@Id
@Column(name = "resource_id", nullable = false)
String resourceId = UUID.randomUUID().toString();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package edu.internet2.tier.shibboleth.admin.ui.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;

import edu.internet2.tier.shibboleth.admin.ui.domain.Group;

public interface GroupRepository extends JpaRepository<Group, String> {
List<Group> findAll();

Group findByResourceId(String id);

@SuppressWarnings("unchecked")
Group save(Group group);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package edu.internet2.tier.shibboleth.admin.ui.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import edu.internet2.tier.shibboleth.admin.ui.domain.Group;
import edu.internet2.tier.shibboleth.admin.ui.repository.GroupRepository;

@Service
public class GroupServiceImpl implements IGroupService {
@Autowired
private GroupRepository repo;

@Override
public Group createOrUpdateGroup(Group group) {
return repo.save(group);
}

@Override
public void deleteDefinition(Group group) {
repo.delete(group);
}

@Override
public Group find(String resourceId) {
return repo.findByResourceId(resourceId);
}

@Override
public List<Group> findAll() {
return repo.findAll();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package edu.internet2.tier.shibboleth.admin.ui.service;

import java.util.List;

import edu.internet2.tier.shibboleth.admin.ui.domain.Group;

public interface IGroupService {

Group createOrUpdateGroup(Group g);

void deleteDefinition(Group g);

Group find(String resourceId);

List<Group> findAll();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package edu.internet2.tier.shibboleth.admin.ui.repository

import javax.persistence.EntityManager

import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.domain.EntityScan
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
import org.springframework.test.context.ContextConfiguration

import edu.internet2.tier.shibboleth.admin.ui.configuration.InternationalizationConfiguration
import edu.internet2.tier.shibboleth.admin.ui.domain.CustomEntityAttributeDefinition
import edu.internet2.tier.shibboleth.admin.ui.domain.Group
import spock.lang.Specification

/**
* Tests to validate the repo and model for groups
* @author chasegawa
*/
@DataJpaTest
@ContextConfiguration(classes=[InternationalizationConfiguration])
@EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"])
@EntityScan("edu.internet2.tier.shibboleth.admin.ui")
class GroupRepositoryTests extends Specification {
@Autowired
GroupRepository repo

@Autowired
EntityManager entityManager

def "simple create test"() {
given:
def group = new Group().with {
it.name = "group-name"
it.description = "some description"
it
}

// Confirm empty state
when:
def groups = repo.findAll()

then:
groups.size() == 0

// save check
when:
repo.save(group)
entityManager.flush()
entityManager.clear()

then:
// save check
def gList = repo.findAll()
gList.size() == 1
def groupFromDb = gList.get(0).asType(Group)
groupFromDb.equals(group) == true

// fetch checks
repo.findByResourceId("not an id") == null
repo.findByResourceId(groupFromDb.resourceId).equals(group)
}

def "expected error"() {
given:
def group = new Group().with {
it.description = "some description"
it
}

// Confirm empty state
when:
def gList = repo.findAll()

then:
gList.size() == 0

// save check
when:
repo.save(group)
entityManager.flush()
entityManager.clear()

then:
// Missing non-nullable field (name) should thrown error
final def exception = thrown(javax.persistence.PersistenceException)
}

def "basic CRUD operations validated"() {
given:
def group = new Group().with {
it.name = "group-name"
it.description = "some description"
it
}

// Confirm empty state
when:
def groups = repo.findAll()

then:
groups.size() == 0

// save check
when:
repo.save(group)
entityManager.flush()
entityManager.clear()

then:
// save check
def gList = repo.findAll()
gList.size() == 1
def groupFromDb = gList.get(0).asType(Group)
groupFromDb.equals(group) == true

// update check
groupFromDb.with {
it.description = "some new text that wasn't there before"
}
groupFromDb.equals(group) == false

when:
repo.save(groupFromDb)
entityManager.flush()
entityManager.clear()

then:
def gList2 = repo.findAll()
gList2.size() == 1
def groupFromDb2 = gList2.get(0).asType(Group)
groupFromDb2.equals(group) == false
groupFromDb2.equals(groupFromDb) == true

// delete tests
when:
repo.delete(groupFromDb2)
entityManager.flush()
entityManager.clear()

then:
repo.findAll().size() == 0
}
}

0 comments on commit c111333

Please sign in to comment.