Skip to content

Commit

Permalink
SHIBUI-2059
Browse files Browse the repository at this point in the history
Initial add of functionality needed on the backend
  • Loading branch information
chasegawa committed Sep 10, 2021
1 parent 8b116e4 commit 6790100
Show file tree
Hide file tree
Showing 9 changed files with 310 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package edu.internet2.tier.shibboleth.admin.ui.controller;

import edu.internet2.tier.shibboleth.admin.ui.service.AttributeBundleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/custom/entity/bundles")
@Slf4j
public class AttributeBundleController {
@Autowired AttributeBundleService attributeBundleService;

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

//POST

//DELETE

//PUT
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package edu.internet2.tier.shibboleth.admin.ui.domain;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import lombok.Data;

import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;

@Entity(name = "attribute_bundle_definition")
@Data
public class AttributeBundle {
@Column(nullable = false)
@ElementCollection
Set<BundleableAttributeType> attributes = new HashSet<>();

@Column(name = "name", nullable = true)
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,38 @@
package edu.internet2.tier.shibboleth.admin.ui.domain;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import edu.internet2.tier.shibboleth.admin.util.BundleableAttributeTypeValueSerializer;

@JsonSerialize(using = BundleableAttributeTypeValueSerializer.class)
public enum BundleableAttributeType {
EDUPERSONPRINCIPALNAME("eduPersonPrincipalName"),
UID("uid"),
MAIL("mail"),
SURNAME("surname"),
GIVENNAME("givenName"),
EDUPERSONAFFILIATE("eduPersonAffiliation"),
EDUPERSONSCOPEDAFFILIATION("eduPersonScopedAffiliation"),
EDUPERSONPRIMARYAFFILIATION("eduPersonPrimaryAffiliation"),
EDUPERSONENTITLEMENT("eduPersonEntitlement"),
EDUPERSONASSURANCE("eduPersonAssurance"),
EDUPERSONUNIQUEID("eduPersonUniqueId"),
EMPLOYEENUMBER("employeeNumber");

String label;

BundleableAttributeType(String val) {
label = val;
}

public String label() {return label;}

public static BundleableAttributeType valueOfLabel(String label) {
for (BundleableAttributeType e : values()) {
if (e.name().equals(label)) {
return e;
}
}
return null;
}

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

import edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBundle;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

/**
* Repository to manage {@link edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBundle} instances.
*/
public interface AttributeBundleRepository extends JpaRepository<AttributeBundle, String> {
List<AttributeBundle> findAll();

AttributeBundle save(AttributeBundle target);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package edu.internet2.tier.shibboleth.admin.ui.service;

import edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBundle;
import edu.internet2.tier.shibboleth.admin.ui.repository.AttributeBundleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class AttributeBundleService {
@Autowired
AttributeBundleRepository attributeBundleRepository;

public List<AttributeBundle> findAll() {
return attributeBundleRepository.findAll();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package edu.internet2.tier.shibboleth.admin.util;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import edu.internet2.tier.shibboleth.admin.ui.domain.BundleableAttributeType;

import java.io.IOException;

/**
* This simplifies translation to the front end. We use the ENUM on the backend, but the <code>BundleableAttributeType</code>
* is tagged to serialize using this helper.
* Note: The deserialize is done naturally by setting <code>spring.jackson.mapper.accept-case-insensitive-enums=true</code> in
* the application.properties and by the setup of the ENUM itself
*/
public class BundleableAttributeTypeValueSerializer extends StdSerializer<BundleableAttributeType> {
public BundleableAttributeTypeValueSerializer() {
this(null);
}

public BundleableAttributeTypeValueSerializer(Class<BundleableAttributeType> t) {
super(t);
}

@Override
public void serialize(BundleableAttributeType value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeString(value.label());
}
}
1 change: 1 addition & 0 deletions backend/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ spring.h2.console.settings.web-allow-others=true

# spring.jackson.default-property-inclusion=non_absent
spring.jackson.default-property-inclusion=NON_NULL
spring.jackson.mapper.accept-case-insensitive-enums=true

# Database Configuration PostgreSQL
#spring.datasource.url=jdbc:postgresql://localhost:5432/shibui
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package edu.internet2.tier.shibboleth.admin.ui.controller

import com.fasterxml.jackson.databind.MapperFeature
import com.fasterxml.jackson.databind.ObjectMapper
import edu.internet2.tier.shibboleth.admin.ui.configuration.ShibUIConfiguration
import edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBundle
import edu.internet2.tier.shibboleth.admin.ui.repository.AttributeBundleRepository
import edu.internet2.tier.shibboleth.admin.ui.service.AttributeBundleService
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.boot.test.context.TestConfiguration
import org.springframework.context.annotation.Bean
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
import org.springframework.test.context.ContextConfiguration
import org.springframework.test.web.servlet.setup.MockMvcBuilders
import org.springframework.transaction.annotation.Transactional
import spock.lang.Specification

import static org.hamcrest.Matchers.containsInAnyOrder
import static org.springframework.http.MediaType.APPLICATION_JSON
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status

@DataJpaTest
@EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"])
@EntityScan("edu.internet2.tier.shibboleth.admin.ui")
@ContextConfiguration(classes = [ShibUIConfiguration, ABCTConfig])
class AttributeBundleControllerTests extends Specification {
@Autowired
AttributeBundleController controller

@Autowired
AttributeBundleRepository attributeBundleRepository

ObjectMapper objectMapper = new ObjectMapper().with {
it.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS)
it
}

def MockMvc

@Transactional
def setup() {
mockMvc = MockMvcBuilders.standaloneSetup(controller).build()
attributeBundleRepository.deleteAll()
}

def "GET checks" () {
expect:
attributeBundleRepository.findAll().isEmpty()

when: "fetch for no bundles"
def result = mockMvc.perform(get('/api/custom/entity/bundles'))

then:
result.andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON))
.andExpect(content().json('[]'))

when: "add a bundle"
def json = """
{
"name": "bundleName",
"resourceId": "randomIDVal",
"attributes": ["eduPersonPrincipalName", "surname", "givenName"]
}
"""

AttributeBundle bundle = objectMapper.readValue(json, AttributeBundle.class)
attributeBundleRepository.saveAndFlush(bundle)
result = mockMvc.perform(get('/api/custom/entity/bundles'))

then:
result.andExpect(status().isOk())
.andExpect(content().contentType(APPLICATION_JSON))
.andExpect(jsonPath("\$.[0].name").value("bundleName"))
.andExpect(jsonPath("\$.[0].resourceId").value("randomIDVal"))
.andExpect(jsonPath("\$.[0].attributes", containsInAnyOrder("eduPersonPrincipalName", "surname", "givenName")))
}

// can go away with merge to develop...
@TestConfiguration
private static class ABCTConfig {
@Bean
AttributeBundleController attributeBundleController(AttributeBundleService attributeBundleService) {
new AttributeBundleController().with {
it.attributeBundleService = attributeBundleService
it
}
}

@Bean
AttributeBundleService attributeBundleService(AttributeBundleRepository repo) {
new AttributeBundleService().with {
it.attributeBundleRepository = repo
it
}
}

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

import com.fasterxml.jackson.databind.MapperFeature
import com.fasterxml.jackson.databind.ObjectMapper
import edu.internet2.tier.shibboleth.admin.ui.configuration.ShibUIConfiguration
import edu.internet2.tier.shibboleth.admin.ui.domain.AttributeBundle
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 spock.lang.Specification

@DataJpaTest
@EnableJpaRepositories(basePackages = ["edu.internet2.tier.shibboleth.admin.ui"])
@EntityScan("edu.internet2.tier.shibboleth.admin.ui")
@ContextConfiguration(classes = [ShibUIConfiguration])
class AttributeBundleRepositoryTests extends Specification {
@Autowired
AttributeBundleRepository abRepo

ObjectMapper objectMapper = new ObjectMapper().with {
it.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS)
it
}

def "test create and fetch" () {
given:
def json = """
{
"name": "bundleName",
"resourceId": "randomIDVal",
"attributes": ["eduPersonPrincipalName", "surname", "givenName"]
}
"""

AttributeBundle bundle = objectMapper.readValue(json, AttributeBundle.class)

when:
def result = abRepo.save(bundle)

then:
result == bundle
}
}

0 comments on commit 6790100

Please sign in to comment.