1

Merge branch 'event-db' into html-gruppe

# Conflicts:
#	src/main/java/mops/gruppen2/controller/Gruppen2Controller.java
#	src/main/java/mops/gruppen2/entities/Teilnehmer.java
This commit is contained in:
killerber4t
2020-03-09 14:34:02 +01:00
43 changed files with 614 additions and 300 deletions

View File

@ -3,11 +3,16 @@ package mops.gruppen2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.Collections;
@SpringBootApplication
@EnableSwagger2
public class Gruppen2Application {
@ -16,8 +21,25 @@ public class Gruppen2Application {
}
@Bean
public Docket productAPI(){
return new Docket(DocumentationType.SWAGGER_2).select()
.apis(RequestHandlerSelectors.basePackage("mops.gruppen2")).build();
public Docket productAPI() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.paths(PathSelectors.ant("/products/**"))
.apis(RequestHandlerSelectors.basePackage("mops.gruppen2"))
.build()
.apiInfo(apiMetadata());
}
private ApiInfo apiMetadata() {
return new ApiInfo(
"Gruppenbildung API",
"API zum anfragen/aktualisieren der Gruppendaten.",
"0.0.1",
"Free to use",
new Contact("gruppen2", "https://github.com/hhu-propra2/abschlussprojekt-it-bois", ""),
"",
"",
Collections.emptyList()
);
}
}

View File

@ -0,0 +1,34 @@
package mops.gruppen2.controller;
import mops.gruppen2.service.KeyCloakService;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.security.RolesAllowed;
@Controller
@RequestMapping("/gruppen2")
public class Gruppen2Controller {
private final KeyCloakService keyCloakService;
public Gruppen2Controller(KeyCloakService keyCloakService) {
this.keyCloakService = keyCloakService;
}
/**Zeigt die index.html an.
*
* @param token toller token
* @param model tolles model
* @return index.html
*/
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator)"})
@GetMapping("")
public String index(KeycloakAuthenticationToken token, Model model) {
model.addAttribute("account", keyCloakService.createAccountFromPrincipal(token));
return "index";
}
}

View File

@ -0,0 +1,72 @@
package mops.gruppen2.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.github.javafaker.Faker;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import mops.gruppen2.domain.ProductSwaggerExample;
import mops.gruppen2.domain.event.AddUserEvent;
import mops.gruppen2.service.SerializationService;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
/**
* Ein Beispiel für eine API mit Swagger.
*/
@RestController
@RequestMapping("/products")
public class SwaggerAPIControllerExample {
private final Faker faker = new Faker();
private final List<ProductSwaggerExample> products = new ArrayList<>();
private final SerializationService serializationService;
public SwaggerAPIControllerExample(SerializationService serializationService) {
this.serializationService = serializationService;
}
@GetMapping("/get/all")
@ApiOperation(value = "Erzeugt eine Liste mit allen gespeicherten Produkten")
public List<ProductSwaggerExample> getProducts() {
return products;
}
@GetMapping("/get/{index}")
public ProductSwaggerExample getProduct(@ApiParam("Produkt Index") @PathVariable int index) {
return products.get(index);
}
@PostMapping("/save")
public String saveProduct(@RequestBody ProductSwaggerExample product) {
products.add(product);
return "Product saved successfully";
}
@PostMapping("/random")
public String saveRandomProduct() {
products.add(new ProductSwaggerExample(faker.food().ingredient(), "Empty"));
return "Product saved successfully";
}
/*@GetMapping("/json") //just for testing
public void json() {
AddUserEvent aEvent = new AddUserEvent(
1,
1,
"Eins",
faker.leagueOfLegends().location(),
faker.name().lastName(),
"123@email.de");
try {
serializationService.serializeEvent(aEvent);
serializationService.saveEvent(aEvent);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}*/
}

View File

@ -1,64 +0,0 @@
package mops.gruppen2.controllers;
import javax.annotation.security.RolesAllowed;
import mops.gruppen2.entities.Gruppe;
import mops.gruppen2.security.Account;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.context.annotation.SessionScope;
@SessionScope
@Controller
public class Gruppen2Controller {
/**
* Creates an Account.
*
* @param token Ein toller token
* @return Account with current userdata
*/
private Account createAccountFromPrincipal(KeycloakAuthenticationToken token) {
KeycloakPrincipal principal = (KeycloakPrincipal) token.getPrincipal();
return new Account(
principal.getName(),
principal.getKeycloakSecurityContext().getIdToken().getEmail(),
null,
principal.getKeycloakSecurityContext().getIdToken().getGivenName(),
principal.getKeycloakSecurityContext().getIdToken().getFamilyName(),
token.getAccount().getRoles());
}
/**Zeigt die index.html an.
*
* @param token toller token
* @param model tolles model
* @return index.html
*/
@GetMapping("/")
@RolesAllowed({"ROLE_orga", "ROLE_studentin", "ROLE_actuator)"})
public String index(KeycloakAuthenticationToken token, Model model) {
model.addAttribute("account", createAccountFromPrincipal(token));
return "index";
}
@PostMapping("/")
public String addGruppe(@ModelAttribute Gruppe gruppe) {
System.out.println(gruppe);
return "redirect:/";
}
@GetMapping("/createGroup")
public String createGruppe(){
return "create";
}
@GetMapping("/findGroup")
public String findGruppe(){
return "search";
}
}

View File

@ -1,24 +0,0 @@
package mops.gruppen2.controllers;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RestController
public class SwaggerAPIController {
@RequestMapping(value = "/products", method = RequestMethod.GET)
public List<String> getProducts(){
List<String> productList = new ArrayList<>();
productList.add("Honey");
productList.add("Almond");
return productList;
}
@RequestMapping(value = "/products", method = RequestMethod.POST)
public String createProduct() {
return "Product is saved successfully";
}
}

View File

@ -0,0 +1,39 @@
package mops.gruppen2.domain;
import lombok.Getter;
import mops.gruppen2.domain.event.Event;
import java.lang.reflect.Method;
import java.util.List;
/**
* Repräsentiert viele Events als aggregiertes Objekt.
*/
@Getter
public abstract class Aggregate {
protected long id;
public void apply(List<Event> events) {
events.forEach(this::applyEvent);
}
public void apply(Event event) {
applyEvent(event);
}
/**
* Ruft die spezifische applyEvent-Methode im entsprechenden Aggregat auf.
*
* @param event Event, welches aggregiert wird
*/
private void applyEvent(Event event) {
try {
Method method = this.getClass().getDeclaredMethod("applyEvent", event.getClass());
method.setAccessible(true);
method.invoke(this, event);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,16 @@
package mops.gruppen2.domain;
import lombok.Data;
import lombok.Value;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;
@Table("event")
@Data
public class EventDTO {
@Id
long event_id;
long group_id;
String user_id;
String event_payload;
}

View File

@ -0,0 +1,74 @@
package mops.gruppen2.domain;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import mops.gruppen2.domain.event.*;
import java.util.*;
/**
* Repräsentiert den aggregierten Zustand einer Gruppe.
*/
@EqualsAndHashCode(callSuper = false)
@Getter
public class Group extends Aggregate {
private String title;
private String description;
private final List<User> members;
private final Map<User, Role> roles;
public Group() {
this.members = new ArrayList<>();
this.roles = new HashMap<>();
}
private void applyEvent(CreateGroupEvent event) {
title = event.getGroupTitle();
description = event.getGroupDescription();
id = event.getGroup_id();
}
private void applyEvent(UpdateRoleEvent event) {
User user;
Optional<User> userOptional = members.stream()
.filter(u -> u.getUser_id().equals(event.getUser_id()))
.findFirst();
if (userOptional.isPresent()) {
user = userOptional.get();
} else {
System.out.println("UserNotFoundException");
return;
}
if (roles.containsKey(user) && event.getNewRole() == Role.STUDENT) {
roles.remove(user);
} else {
roles.put(user, event.getNewRole());
}
}
private void applyEvent(AddUserEvent event) {
User user = new User(event.getUser_id(), event.getGivenname(), event.getFamilyname(), event.getEmail());
this.members.add(user);
}
private void applyEvent(UpdateGroupTitleEvent event) {
this.title = event.getNewGroupTitle();
}
private void applyEvent(UpdateGroupDescriptionEvent event) {
this.description = event.getNewGroupDescription();
}
private void applyEvent(DeleteUserEvent event) {
for (User user : members) {
if (user.getUser_id().equals(event.getUser_id())) {
this.members.remove(user);
break;
}
}
}
}

View File

@ -0,0 +1,12 @@
package mops.gruppen2.domain;
import lombok.Value;
// @ApiModelProperty
@Value
public class ProductSwaggerExample {
// @ApiModelProperty
String name;
String description;
}

View File

@ -0,0 +1,5 @@
package mops.gruppen2.domain;
public enum Role {
ORGA, ADMIN, STUDENT
}

View File

@ -0,0 +1,14 @@
package mops.gruppen2.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class User {
String user_id;
String givenname;
String familyname;
String email;
}

View File

@ -0,0 +1,30 @@
package mops.gruppen2.domain.event;
import lombok.EqualsAndHashCode;
import lombok.Value;
import mops.gruppen2.domain.User;
/**
* Fügt einen einzelnen Nutzer einer Gruppe hinzu.
*/
@EqualsAndHashCode(callSuper = true)
@Value
public class AddUserEvent extends Event {
String givenname;
String familyname;
String email;
public AddUserEvent(long event_id, long group_id, String user_id, String givenname, String familyname, String email) {
super(event_id, group_id, user_id);
this.givenname = givenname;
this.familyname = familyname;
this.email = email;
}
public AddUserEvent(long event_id, long group_id, User user) {
super(event_id, group_id, user.getUser_id());
this.givenname = user.getGivenname();
this.familyname = user.getFamilyname();
this.email = user.getEmail();
}
}

View File

@ -0,0 +1,17 @@
package mops.gruppen2.domain.event;
import lombok.EqualsAndHashCode;
import lombok.Value;
@EqualsAndHashCode(callSuper = true)
@Value
public class CreateGroupEvent extends Event {
String groupTitle;
String groupDescription;
public CreateGroupEvent(long event_id, long group_id, String user_id, String groupTitle, String groupDescription) {
super(event_id, group_id, user_id);
this.groupTitle = groupTitle;
this.groupDescription = groupDescription;
}
}

View File

@ -0,0 +1,16 @@
package mops.gruppen2.domain.event;
import lombok.EqualsAndHashCode;
import lombok.Value;
/**
* Entfernt ein einzelnes Mitglied einer Gruppe.
*/
@EqualsAndHashCode(callSuper = true)
@Value
public class DeleteUserEvent extends Event {
public DeleteUserEvent(long event_id, long group_id, String user_id) {
super(event_id, group_id, user_id);
}
}

View File

@ -0,0 +1,14 @@
package mops.gruppen2.domain.event;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import lombok.Value;
import lombok.experimental.NonFinal;
@Value
@NonFinal
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME)
public class Event {
long event_id;
long group_id;
String user_id;
}

View File

@ -0,0 +1,18 @@
package mops.gruppen2.domain.event;
import lombok.EqualsAndHashCode;
import lombok.Value;
/**
* Ändert nur die Gruppenbeschreibung.
*/
@EqualsAndHashCode(callSuper = true)
@Value
public class UpdateGroupDescriptionEvent extends Event {
String newGroupDescription;
public UpdateGroupDescriptionEvent(long event_id, long group_id, String user_id, String newGroupDescription) {
super(event_id, group_id, user_id);
this.newGroupDescription = newGroupDescription;
}
}

View File

@ -0,0 +1,18 @@
package mops.gruppen2.domain.event;
import lombok.EqualsAndHashCode;
import lombok.Value;
/**
* Ändert nur den Gruppentitel.
*/
@EqualsAndHashCode(callSuper = true)
@Value
public class UpdateGroupTitleEvent extends Event {
String newGroupTitle;
public UpdateGroupTitleEvent(long event_id, long group_id, String user_id, String newGroupTitle) {
super(event_id, group_id, user_id);
this.newGroupTitle = newGroupTitle;
}
}

View File

@ -0,0 +1,21 @@
package mops.gruppen2.domain.event;
import lombok.EqualsAndHashCode;
import lombok.Value;
import mops.gruppen2.domain.Role;
/**
* Aktualisiert die Gruppenrolle eines Teilnehmers.
*/
@EqualsAndHashCode(callSuper = true)
@Value
public class UpdateRoleEvent extends Event {
Role newRole;
public UpdateRoleEvent(long event_id, long group_id, String user_id, Role newRole) {
super(event_id, group_id, user_id);
this.newRole = newRole;
}
}

View File

@ -1,4 +0,0 @@
package mops.gruppen2.entities;
public class Admin extends Rolle {
}

View File

@ -1,18 +0,0 @@
package mops.gruppen2.entities;
import mops.gruppen2.events.Event;
import java.lang.reflect.Method;
public abstract class Aggregat {
public void applyEvent(Event event) {
try {
Method method = this.getClass().getDeclaredMethod("applyEvent", event.getClass());
method.setAccessible(true);
method.invoke(this, event);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -1,21 +0,0 @@
package mops.gruppen2.entities;
import lombok.Data;
import mops.gruppen2.events.CreateGroupEvent;
import java.util.List;
@Data
public class Gruppe extends Aggregat {
long id;
String titel;
String beschreibung;
List<Teilnehmer> teilnehmersList;
public void applyEvent(CreateGroupEvent event){
this.id = event.getId();
this.titel = event.getTitel();
this.beschreibung = event.getBeschreibung();
this.teilnehmersList= null;
}
}

View File

@ -1,4 +0,0 @@
package mops.gruppen2.entities;
public class Orga extends Rolle {
}

View File

@ -1,5 +0,0 @@
package mops.gruppen2.entities;
public class Rolle {
}

View File

@ -1,21 +0,0 @@
package mops.gruppen2.entities;
import lombok.Data;
import org.springframework.data.annotation.Id;
import java.util.List;
@Data
public class Teilnehmer {
@Id
Long id;
String vorname;
String nachname;
String email;
List<Gruppe> Gruppen;
public Teilnehmer(String vorname, String nachname) {
this.vorname = vorname;
this.nachname = nachname;
}
}

View File

@ -1,15 +0,0 @@
package mops.gruppen2.events;
import lombok.Getter;
@Getter
public class CreateGroupEvent extends Event {
String titel;
String beschreibung;
public CreateGroupEvent(long id, long gruppe_id, long user_id, String titel, String beschreibung) {
super(id, gruppe_id, user_id);
this.titel = titel;
this.beschreibung = beschreibung;
}
}

View File

@ -1,12 +0,0 @@
package mops.gruppen2.events;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class Event {
long id;
long gruppe_id;
long user_id;
}

View File

@ -1,7 +0,0 @@
package mops.gruppen2.repositories;
import mops.gruppen2.events.Event;
import org.springframework.data.repository.CrudRepository;
public interface EventRepository extends CrudRepository<Event, Long> {
}

View File

@ -0,0 +1,8 @@
package mops.gruppen2.repository;
import mops.gruppen2.domain.EventDTO;
import mops.gruppen2.domain.event.Event;
import org.springframework.data.repository.CrudRepository;
public interface EventRepository extends CrudRepository<EventDTO, Long> {
}

View File

@ -6,7 +6,11 @@ import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticatio
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.keycloak.representations.AccessToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
@ -70,8 +74,6 @@ class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
http.headers().frameOptions().disable();
}
/**
* Declaring this class enables us to use the Spring specific
* {@link org.springframework.security.access.annotation.Secured} annotation

View File

@ -0,0 +1,23 @@
package mops.gruppen2.service;
import mops.gruppen2.domain.Group;
import mops.gruppen2.domain.event.Event;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class GroupService {
/**
* Konstruiert eine vollständige Gruppe aus Events, welche dieselbe Gruppe betreffen.
*
* @param eventList Die Events für diese Gruppe
* @return Gruppe auf aktuellem Stand
*/
Group buildGroupFromEvents(List<Event> eventList) {
Group newGroup = new Group();
newGroup.apply(eventList);
return newGroup;
}
}

View File

@ -1,4 +1,4 @@
package mops.gruppen2.services;
package mops.gruppen2.service;
import mops.gruppen2.security.Account;
import org.keycloak.KeycloakPrincipal;

View File

@ -0,0 +1,44 @@
package mops.gruppen2.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import mops.gruppen2.domain.EventDTO;
import mops.gruppen2.domain.event.Event;
import mops.gruppen2.repository.EventRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
/**
* Übersetzt JSON-Event-Payloads zu Java-Event-Repräsentationen und zurück.
*/
@Service
public class SerializationService {
private final EventRepository eventStore;
private final Logger log = LoggerFactory.getLogger(SerializationService.class);
public SerializationService(EventRepository eventStore) {
this.eventStore = eventStore;
}
public String serializeEvent(Event event) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(event);
log.info(json);
return json;
}
public void saveEvent(Event event){
try {
EventDTO eventDTO = new EventDTO();
eventDTO.setGroup_id(event.getGroup_id());
eventDTO.setUser_id(event.getUser_id());
eventDTO.setEvent_payload(serializeEvent(event));
eventStore.save(eventDTO);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
}

View File

@ -1,28 +0,0 @@
package mops.gruppen2.services;
import mops.gruppen2.events.CreateGroupEvent;
import mops.gruppen2.events.Event;
import mops.gruppen2.entities.Gruppe;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class GruppenService {
CreateGroupEvent createGroupEvent = new CreateGroupEvent(1L,1L,1L,"hello", "foo");
public GruppenService(){
List<Event> eventList = new ArrayList<>();
eventList.add(createGroupEvent);
Gruppe newGroup = buildGroup(eventList);
System.out.println(newGroup.toString());
}
Gruppe buildGroup(List<Event> eventList){
Gruppe newGroup = new Gruppe();
eventList.forEach(newGroup::applyEvent);
return newGroup;
}
}

View File

@ -1,10 +0,0 @@
package mops.gruppen2.services;
import org.springframework.stereotype.Service;
/**
* Übersetzt und baut
*/
@Service
public class SerializationService {
}

View File

@ -14,4 +14,3 @@ keycloak.auth-server-url=https://keycloak.cs.hhu.de/auth
keycloak.realm=MOPS
keycloak.resource=demo
keycloak.public-client=true

View File

@ -1,4 +0,0 @@
-- noinspection SqlNoDataSourceInspectionForFile
insert into TEILNEHMER (VORNAME, NACHNAME, EMAIL) values
('Peter', 'Müller', 'Peter@123.de');

View File

@ -1,25 +1,11 @@
-- noinspection SqlNoDataSourceInspectionForFile
DROP TABLE IF EXISTS teilnehmer;
CREATE TABLE teilnehmer (
teilnehmer_id INT PRIMARY KEY AUTO_INCREMENT,
vorname VARCHAR(50) NOT NULL,
nachname VARCHAR(50) NOT NULL ,
email VARCHAR(255) NOT NULL
);
DROP TABLE IF EXISTS event;
DROP TABLE IF EXISTS gruppe;
CREATE TABLE gruppe
CREATE TABLE event
(
gruppe_id INTEGER PRIMARY KEY auto_increment,
titel TEXT NOT NULL,
beschreibung TEXT NOT NULL
);
DROP TABLE IF EXISTS teilnahme;
CREATE TABLE teilnahme
(
id INTEGER PRIMARY KEY auto_increment,
teilnehmer_dto INTEGER REFERENCES teilnehmer(teilnehmer_id),
gruppe_dto INTEGER REFERENCES gruppe(gruppe_id)
event_id INT PRIMARY KEY AUTO_INCREMENT,
group_id INT NOT NULL,
user_id VARCHAR(50),
event_payload VARCHAR(255)
);