Skip to content
Snippets Groups Projects
Verified Commit a414f33e authored by Martin Weise's avatar Martin Weise
Browse files

Lots of refactoring

parent 452e370c
Branches
Tags
1 merge request!371Hotfix the wrong user id, ref #480
Showing
with 299 additions and 366 deletions
...@@ -60,6 +60,8 @@ ...@@ -60,6 +60,8 @@
<!-- see https://github.com/apache/spark/blob/cde8e4a82e20a363861f451ebd5138efb3194ab8/pom.xml --> <!-- see https://github.com/apache/spark/blob/cde8e4a82e20a363861f451ebd5138efb3194ab8/pom.xml -->
<hadoop.version>3.4.0</hadoop.version> <hadoop.version>3.4.0</hadoop.version>
<jakarta-servlet.version>5.0.0</jakarta-servlet.version> <jakarta-servlet.version>5.0.0</jakarta-servlet.version>
<sonar.coverage.jacoco.xmlReportPaths>./report/target/site/jacoco-aggregate/jacoco.xml
</sonar.coverage.jacoco.xmlReportPaths>
</properties> </properties>
<dependencies> <dependencies>
......
...@@ -32,14 +32,11 @@ import static jakarta.persistence.GenerationType.IDENTITY; ...@@ -32,14 +32,11 @@ import static jakarta.persistence.GenerationType.IDENTITY;
@UniqueConstraint(columnNames = {"cid", "internalName"}) @UniqueConstraint(columnNames = {"cid", "internalName"})
}) })
@NamedQueries({ @NamedQueries({
@NamedQuery(name = "Database.findAllDesc", query = "select d from Database d order by d.created desc"), @NamedQuery(name = "Database.findAllDesc", query = "select distinct d from Database d order by d.id desc"),
@NamedQuery(name = "Database.findByInternalName", query = "select d from Database d where d.internalName = ?1"), @NamedQuery(name = "Database.findAllPublicDesc", query = "select distinct d from Database d where d.isPublic = true order by d.id desc"),
@NamedQuery(name = "Database.findAllOnlyIds", query = "select d.id from Database d order by d.created desc"), @NamedQuery(name = "Database.findAllPublicOrReadAccessDesc", query = "select distinct d from Database d where d.isPublic = true or exists(select a.hdbid from DatabaseAccess a where a.huserid = ?1 and a.hdbid = d.id) order by d.id desc"),
@NamedQuery(name = "Database.findReadAccess", query = "select distinct d from Database d join DatabaseAccess a on a.hdbid = d.id and a.huserid = ?1"), @NamedQuery(name = "Database.findAllPublicOrReadAccessByInternalNameDesc", query = "select distinct d from Database d where d.isPublic = true and d.internalName = ?2 or exists(select a.hdbid from DatabaseAccess a where a.huserid = ?1 and a.hdbid = d.id) order by d.id desc"),
@NamedQuery(name = "Database.findWriteAccess", query = "select distinct d from Database d join DatabaseAccess a on a.hdbid = d.id and a.huserid = ?1 where a.type = 'WRITE_OWN' or a.type = 'WRITE_ALL'"), @NamedQuery(name = "Database.findAllPublicByInternalNameDesc", query = "select distinct d from Database d where d.isPublic = true and d.internalName = ?1 order by d.id desc"),
@NamedQuery(name = "Database.findConfigureAccess", query = "select distinct d from Database d where d.ownedBy = ?1"),
@NamedQuery(name = "Database.findPublicOrMine", query = "select distinct d from Database d where d.id = ?1 and (d.isPublic = true or d.ownedBy = ?2)"),
@NamedQuery(name = "Database.findPublic", query = "select distinct d from Database d where d.isPublic = true and d.id = ?1"),
}) })
public class Database implements Serializable { public class Database implements Serializable {
......
...@@ -60,6 +60,8 @@ ...@@ -60,6 +60,8 @@
<aws-s3.version>2.25.23</aws-s3.version> <aws-s3.version>2.25.23</aws-s3.version>
<jackson.version>2.15.2</jackson.version> <jackson.version>2.15.2</jackson.version>
<minio.version>8.5.7</minio.version> <minio.version>8.5.7</minio.version>
<sonar.coverage.jacoco.xmlReportPaths>./report/target/site/jacoco-aggregate/jacoco.xml
</sonar.coverage.jacoco.xmlReportPaths>
</properties> </properties>
<dependencies> <dependencies>
......
...@@ -858,18 +858,7 @@ public interface MetadataMapper { ...@@ -858,18 +858,7 @@ public interface MetadataMapper {
LanguageType languageTypeDtoToLanguageType(LanguageTypeDto data); LanguageType languageTypeDtoToLanguageType(LanguageTypeDto data);
default Boolean onlyIsPublicOrOwner(Boolean isPublic, User caller, User owner, User databaseOwner) { default DatabaseDto customDatabaseToDatabaseDto(Database data) {
if (isPublic) {
return true;
}
/* private schema */
if (caller == null) {
return false;
}
return owner.equals(caller) || databaseOwner.equals(caller);
}
default DatabaseDto customDatabaseToDatabaseDto(Database data, User caller) {
if (data == null) { if (data == null) {
return null; return null;
} }
...@@ -899,14 +888,12 @@ public interface MetadataMapper { ...@@ -899,14 +888,12 @@ public interface MetadataMapper {
if (data.getTables() != null) { if (data.getTables() != null) {
database.setTables(new LinkedList<>(data.getTables() database.setTables(new LinkedList<>(data.getTables()
.stream() .stream()
.filter(t -> onlyIsPublicOrOwner(t.getIsSchemaPublic() || t.getIsPublic(), caller, t.getOwner(), t.getDatabase().getOwner()))
.map(this::tableToTableBriefDto) .map(this::tableToTableBriefDto)
.toList())); .toList()));
} }
if (data.getViews() != null) { if (data.getViews() != null) {
database.setViews(new LinkedList<>(data.getViews() database.setViews(new LinkedList<>(data.getViews()
.stream() .stream()
.filter(v -> onlyIsPublicOrOwner(v.getIsSchemaPublic() || v.getIsPublic(), caller, v.getOwner(), v.getDatabase().getOwner()))
.map(this::viewToViewBriefDto) .map(this::viewToViewBriefDto)
.toList())); .toList()));
} }
......
...@@ -13,18 +13,12 @@ public interface DatabaseRepository extends JpaRepository<Database, Long> { ...@@ -13,18 +13,12 @@ public interface DatabaseRepository extends JpaRepository<Database, Long> {
List<Database> findAllDesc(); List<Database> findAllDesc();
List<Database> findReadAccess(UUID id); List<Database> findAllPublicDesc();
List<Database> findWriteAccess(UUID id); List<Database> findAllPublicOrReadAccessDesc(UUID id);
List<Database> findConfigureAccess(UUID id); List<Database> findAllPublicOrReadAccessByInternalNameDesc(UUID id, String internalName);
List<Long> findAllOnlyIds(); List<Database> findAllPublicByInternalNameDesc(String internalName);
Optional<Database> findPublicOrMine(Long databaseId, UUID id);
Optional<Database> findPublic(Long databaseId);
Optional<Database> findByInternalName(String internalName);
} }
package at.tuwien.utils; package at.tuwien.endpoints;
import at.tuwien.api.user.UserDetailsDto; import at.tuwien.api.user.UserDetailsDto;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
...@@ -6,9 +6,9 @@ import org.springframework.security.core.Authentication; ...@@ -6,9 +6,9 @@ import org.springframework.security.core.Authentication;
import java.security.Principal; import java.security.Principal;
import java.util.UUID; import java.util.UUID;
public class UserUtil { public abstract class AbstractEndpoint {
public static boolean hasRole(Principal principal, String role) { public boolean hasRole(Principal principal, String role) {
if (principal == null || role == null) { if (principal == null || role == null) {
return false; return false;
} }
...@@ -18,7 +18,7 @@ public class UserUtil { ...@@ -18,7 +18,7 @@ public class UserUtil {
.anyMatch(a -> a.getAuthority().equals(role)); .anyMatch(a -> a.getAuthority().equals(role));
} }
public static boolean isSystem(Principal principal) { public boolean isSystem(Principal principal) {
if (principal == null) { if (principal == null) {
return false; return false;
} }
...@@ -28,7 +28,7 @@ public class UserUtil { ...@@ -28,7 +28,7 @@ public class UserUtil {
.anyMatch(a -> a.getAuthority().equals("system")); .anyMatch(a -> a.getAuthority().equals("system"));
} }
public static UUID getId(Principal principal) { public UUID getId(Principal principal) {
if (principal == null) { if (principal == null) {
return null; return null;
} }
......
...@@ -11,7 +11,6 @@ import at.tuwien.mapper.MetadataMapper; ...@@ -11,7 +11,6 @@ import at.tuwien.mapper.MetadataMapper;
import at.tuwien.service.AccessService; import at.tuwien.service.AccessService;
import at.tuwien.service.DatabaseService; import at.tuwien.service.DatabaseService;
import at.tuwien.service.UserService; import at.tuwien.service.UserService;
import at.tuwien.utils.UserUtil;
import io.micrometer.observation.annotation.Observed; import io.micrometer.observation.annotation.Observed;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Content;
...@@ -35,7 +34,7 @@ import java.util.UUID; ...@@ -35,7 +34,7 @@ import java.util.UUID;
@RestController @RestController
@CrossOrigin(origins = "*") @CrossOrigin(origins = "*")
@RequestMapping(path = "/api/database/{databaseId}/access") @RequestMapping(path = "/api/database/{databaseId}/access")
public class AccessEndpoint { public class AccessEndpoint extends AbstractEndpoint {
private final UserService userService; private final UserService userService;
private final AccessService accessService; private final AccessService accessService;
...@@ -99,8 +98,7 @@ public class AccessEndpoint { ...@@ -99,8 +98,7 @@ public class AccessEndpoint {
log.debug("endpoint give access to database, databaseId={}, userId={}, access.type={}", databaseId, userId, log.debug("endpoint give access to database, databaseId={}, userId={}, access.type={}", databaseId, userId,
data.getType()); data.getType());
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final User caller = userService.findByUsername(principal.getName()); if (!database.getOwner().getId().equals(getId(principal))) {
if (!database.getOwner().getId().equals(caller.getId())) {
log.error("Failed to create access: not owner"); log.error("Failed to create access: not owner");
throw new NotAllowedException("Failed to create access: not owner"); throw new NotAllowedException("Failed to create access: not owner");
} }
...@@ -162,8 +160,7 @@ public class AccessEndpoint { ...@@ -162,8 +160,7 @@ public class AccessEndpoint {
log.debug("endpoint modify database access, databaseId={}, userId={}, access.type={}, principal.name={}", log.debug("endpoint modify database access, databaseId={}, userId={}, access.type={}, principal.name={}",
databaseId, userId, data.getType(), principal.getName()); databaseId, userId, data.getType(), principal.getName());
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final User caller = userService.findByUsername(principal.getName()); if (!database.getOwner().getId().equals(getId(principal))) {
if (!database.getOwner().getId().equals(caller.getId())) {
log.error("Failed to update access: not owner"); log.error("Failed to update access: not owner");
throw new NotAllowedException("Failed to update access: not owner"); throw new NotAllowedException("Failed to update access: not owner");
} }
...@@ -204,9 +201,8 @@ public class AccessEndpoint { ...@@ -204,9 +201,8 @@ public class AccessEndpoint {
UserNotFoundException, AccessNotFoundException, NotAllowedException { UserNotFoundException, AccessNotFoundException, NotAllowedException {
log.debug("endpoint get database access, databaseId={}, userId={}, principal.name={}", databaseId, userId, log.debug("endpoint get database access, databaseId={}, userId={}, principal.name={}", databaseId, userId,
principal.getName()); principal.getName());
final User caller = userService.findByUsername(principal.getName()); if (!userId.equals(getId(principal))) {
if (!userId.equals(caller.getId())) { if (!hasRole(principal, "check-foreign-database-access")) {
if (!UserUtil.hasRole(principal, "check-foreign-database-access")) {
log.error("Failed to find access: foreign user"); log.error("Failed to find access: foreign user");
throw new NotAllowedException("Failed to find access: foreign user"); throw new NotAllowedException("Failed to find access: foreign user");
} }
...@@ -261,8 +257,7 @@ public class AccessEndpoint { ...@@ -261,8 +257,7 @@ public class AccessEndpoint {
SearchServiceException, SearchServiceConnectionException { SearchServiceException, SearchServiceConnectionException {
log.debug("endpoint revoke database access, databaseId={}, userId={}", databaseId, userId); log.debug("endpoint revoke database access, databaseId={}, userId={}", databaseId, userId);
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final User caller = userService.findByUsername(principal.getName()); if (!database.getOwner().getId().equals(getId(principal))) {
if (!database.getOwner().getId().equals(caller.getId())) {
log.error("Failed to revoke access: not owner"); log.error("Failed to revoke access: not owner");
throw new NotAllowedException("Failed to revoke access: not owner"); throw new NotAllowedException("Failed to revoke access: not owner");
} }
......
...@@ -14,7 +14,10 @@ import lombok.extern.log4j.Log4j2; ...@@ -14,7 +14,10 @@ import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List; import java.util.List;
...@@ -22,7 +25,7 @@ import java.util.List; ...@@ -22,7 +25,7 @@ import java.util.List;
@CrossOrigin(origins = "*") @CrossOrigin(origins = "*")
@RestController @RestController
@RequestMapping(path = "/api/concept") @RequestMapping(path = "/api/concept")
public class ConceptEndpoint { public class ConceptEndpoint extends AbstractEndpoint {
private final ConceptService conceptService; private final ConceptService conceptService;
private final MetadataMapper metadataMapper; private final MetadataMapper metadataMapper;
...@@ -47,13 +50,11 @@ public class ConceptEndpoint { ...@@ -47,13 +50,11 @@ public class ConceptEndpoint {
}) })
public ResponseEntity<List<ConceptDto>> findAll() { public ResponseEntity<List<ConceptDto>> findAll() {
log.debug("endpoint list concepts"); log.debug("endpoint list concepts");
final List<ConceptDto> dtos = conceptService.findAll() return ResponseEntity.ok()
.body(conceptService.findAll()
.stream() .stream()
.map(metadataMapper::tableColumnConceptToConceptDto) .map(metadataMapper::tableColumnConceptToConceptDto)
.toList(); .toList());
log.trace("Find all concepts resulted in dtos {}", dtos);
return ResponseEntity.ok()
.body(dtos);
} }
} }
...@@ -10,7 +10,6 @@ import at.tuwien.exception.ContainerNotFoundException; ...@@ -10,7 +10,6 @@ import at.tuwien.exception.ContainerNotFoundException;
import at.tuwien.exception.ImageNotFoundException; import at.tuwien.exception.ImageNotFoundException;
import at.tuwien.mapper.MetadataMapper; import at.tuwien.mapper.MetadataMapper;
import at.tuwien.service.ContainerService; import at.tuwien.service.ContainerService;
import at.tuwien.utils.UserUtil;
import io.micrometer.observation.annotation.Observed; import io.micrometer.observation.annotation.Observed;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.ArraySchema;
...@@ -40,7 +39,7 @@ import java.util.stream.Collectors; ...@@ -40,7 +39,7 @@ import java.util.stream.Collectors;
@CrossOrigin(origins = "*") @CrossOrigin(origins = "*")
@ControllerAdvice @ControllerAdvice
@RequestMapping(path = "/api/container") @RequestMapping(path = "/api/container")
public class ContainerEndpoint { public class ContainerEndpoint extends AbstractEndpoint {
private final MetadataMapper metadataMapper; private final MetadataMapper metadataMapper;
private final ContainerService containerService; private final ContainerService containerService;
...@@ -65,13 +64,11 @@ public class ContainerEndpoint { ...@@ -65,13 +64,11 @@ public class ContainerEndpoint {
}) })
public ResponseEntity<List<ContainerBriefDto>> findAll(@RequestParam(required = false) Integer limit) { public ResponseEntity<List<ContainerBriefDto>> findAll(@RequestParam(required = false) Integer limit) {
log.debug("endpoint find all containers, limit={}", limit); log.debug("endpoint find all containers, limit={}", limit);
final List<ContainerBriefDto> dtos = containerService.getAll(limit) return ResponseEntity.ok()
.body(containerService.getAll(limit)
.stream() .stream()
.map(metadataMapper::containerToContainerBriefDto) .map(metadataMapper::containerToContainerBriefDto)
.collect(Collectors.toList()); .collect(Collectors.toList()));
log.debug("find all containers resulted in {} container(s)", dtos.size());
return ResponseEntity.ok()
.body(dtos);
} }
@PostMapping @PostMapping
...@@ -111,11 +108,8 @@ public class ContainerEndpoint { ...@@ -111,11 +108,8 @@ public class ContainerEndpoint {
public ResponseEntity<ContainerDto> create(@Valid @RequestBody ContainerCreateDto data) public ResponseEntity<ContainerDto> create(@Valid @RequestBody ContainerCreateDto data)
throws ImageNotFoundException, ContainerAlreadyExistsException { throws ImageNotFoundException, ContainerAlreadyExistsException {
log.debug("endpoint create container, data={}", data); log.debug("endpoint create container, data={}", data);
final Container container = containerService.create(data);
final ContainerDto dto = metadataMapper.containerToContainerDto(container);
log.trace("create container resulted in container {}", dto);
return ResponseEntity.status(HttpStatus.CREATED) return ResponseEntity.status(HttpStatus.CREATED)
.body(dto); .body(metadataMapper.containerToContainerDto(containerService.create(data)));
} }
@GetMapping("/{containerId}") @GetMapping("/{containerId}")
...@@ -140,10 +134,8 @@ public class ContainerEndpoint { ...@@ -140,10 +134,8 @@ public class ContainerEndpoint {
throws ContainerNotFoundException { throws ContainerNotFoundException {
log.debug("endpoint find container, containerId={}", containerId); log.debug("endpoint find container, containerId={}", containerId);
final Container container = containerService.find(containerId); final Container container = containerService.find(containerId);
final ContainerDto dto = metadataMapper.containerToContainerDto(container);
log.trace("find container resulted in container {}", dto);
final HttpHeaders headers = new HttpHeaders(); final HttpHeaders headers = new HttpHeaders();
if (UserUtil.isSystem(principal)) { if (isSystem(principal)) {
log.trace("attach privileged credential information"); log.trace("attach privileged credential information");
headers.set("X-Username", container.getPrivilegedUsername()); headers.set("X-Username", container.getPrivilegedUsername());
headers.set("X-Password", container.getPrivilegedPassword()); headers.set("X-Password", container.getPrivilegedPassword());
...@@ -151,7 +143,7 @@ public class ContainerEndpoint { ...@@ -151,7 +143,7 @@ public class ContainerEndpoint {
} }
return ResponseEntity.ok() return ResponseEntity.ok()
.headers(headers) .headers(headers)
.body(dto); .body(metadataMapper.containerToContainerDto(container));
} }
@DeleteMapping("/{containerId}") @DeleteMapping("/{containerId}")
...@@ -175,10 +167,10 @@ public class ContainerEndpoint { ...@@ -175,10 +167,10 @@ public class ContainerEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<Void> delete(@NotNull @PathVariable("containerId") Long containerId) throws ContainerNotFoundException { public ResponseEntity<Void> delete(@NotNull @PathVariable("containerId") Long containerId)
throws ContainerNotFoundException {
log.debug("endpoint delete container, containerId={}", containerId); log.debug("endpoint delete container, containerId={}", containerId);
final Container container = containerService.find(containerId); containerService.remove(containerService.find(containerId));
containerService.remove(container);
return ResponseEntity.accepted() return ResponseEntity.accepted()
.build(); .build();
} }
......
...@@ -8,8 +8,10 @@ import at.tuwien.entities.database.DatabaseAccess; ...@@ -8,8 +8,10 @@ import at.tuwien.entities.database.DatabaseAccess;
import at.tuwien.entities.user.User; import at.tuwien.entities.user.User;
import at.tuwien.exception.*; import at.tuwien.exception.*;
import at.tuwien.mapper.MetadataMapper; import at.tuwien.mapper.MetadataMapper;
import at.tuwien.service.*; import at.tuwien.service.ContainerService;
import at.tuwien.utils.UserUtil; import at.tuwien.service.DatabaseService;
import at.tuwien.service.StorageService;
import at.tuwien.service.UserService;
import io.micrometer.observation.annotation.Observed; import io.micrometer.observation.annotation.Observed;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.headers.Header; import io.swagger.v3.oas.annotations.headers.Header;
...@@ -32,29 +34,25 @@ import org.springframework.transaction.annotation.Transactional; ...@@ -32,29 +34,25 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.security.Principal; import java.security.Principal;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.Optional;
@Log4j2 @Log4j2
@RestController @RestController
@CrossOrigin(origins = "*") @CrossOrigin(origins = "*")
@RequestMapping(path = "/api/database") @RequestMapping(path = "/api/database")
public class DatabaseEndpoint { public class DatabaseEndpoint extends AbstractEndpoint {
private final UserService userService; private final UserService userService;
private final AccessService accessService;
private final MetadataMapper databaseMapper; private final MetadataMapper databaseMapper;
private final StorageService storageService; private final StorageService storageService;
private final DatabaseService databaseService; private final DatabaseService databaseService;
private final ContainerService containerService; private final ContainerService containerService;
@Autowired @Autowired
public DatabaseEndpoint(UserService userService, AccessService accessService, MetadataMapper databaseMapper, public DatabaseEndpoint(UserService userService, MetadataMapper databaseMapper, StorageService storageService,
StorageService storageService, DatabaseService databaseService, DatabaseService databaseService, ContainerService containerService) {
ContainerService containerService) {
this.userService = userService; this.userService = userService;
this.accessService = accessService;
this.databaseMapper = databaseMapper; this.databaseMapper = databaseMapper;
this.storageService = storageService; this.storageService = storageService;
this.databaseService = databaseService; this.databaseService = databaseService;
...@@ -75,28 +73,36 @@ public class DatabaseEndpoint { ...@@ -75,28 +73,36 @@ public class DatabaseEndpoint {
mediaType = "application/json", mediaType = "application/json",
array = @ArraySchema(schema = @Schema(implementation = DatabaseDto.class)))}), array = @ArraySchema(schema = @Schema(implementation = DatabaseDto.class)))}),
}) })
public ResponseEntity<List<DatabaseBriefDto>> list(@RequestParam(name = "internal_name", required = false) String internalName) { public ResponseEntity<List<DatabaseBriefDto>> list(@RequestParam(name = "internal_name", required = false) String internalName,
Principal principal) throws UserNotFoundException,
DatabaseNotFoundException {
log.debug("endpoint list databases, internalName={}", internalName); log.debug("endpoint list databases, internalName={}", internalName);
List<DatabaseBriefDto> dtos = new LinkedList<>(); final List<Database> databases;
if (principal != null) {
if (internalName != null) { if (internalName != null) {
try { log.debug("filter request to contain only public databases or where user with id {} has at least read access that match internal name {}", getId(principal), internalName);
dtos = List.of(databaseMapper.databaseToDatabaseBriefDto(databaseService.findByInternalName(internalName))); databases = databaseService.findAllPublicOrReadAccessByInternalName(getId(principal), internalName);
} catch (DatabaseNotFoundException e) { } else {
/* ignore */ log.debug("filter request to contain only public databases or where user with id {} has at least read access", getId(principal));
databases = databaseService.findAllPublicOrReadAccess(getId(principal));
} }
} else { } else {
dtos = databaseService.findAll() if (internalName != null) {
.stream() log.debug("filter request to contain only public databases that match internal name {}", internalName);
.map(databaseMapper::databaseToDatabaseBriefDto) databases = databaseService.findAllPublicByInternalName(internalName);
.toList(); } else {
log.debug("filter request to contain only public databases");
databases = databaseService.findAllPublic();
}
} }
log.trace("list databases resulted in {} database(s)", dtos.size());
final HttpHeaders headers = new HttpHeaders(); final HttpHeaders headers = new HttpHeaders();
headers.set("X-Count", "" + dtos.size()); headers.set("X-Count", "" + databases.size());
headers.set("Access-Control-Expose-Headers", "X-Count"); headers.set("Access-Control-Expose-Headers", "X-Count");
return ResponseEntity.status(HttpStatus.OK) return ResponseEntity.status(HttpStatus.OK)
.headers(headers) .headers(headers)
.body(dtos); .body(databases.stream()
.map(databaseMapper::databaseToDatabaseBriefDto)
.toList());
} }
@PostMapping @PostMapping
...@@ -150,20 +156,19 @@ public class DatabaseEndpoint { ...@@ -150,20 +156,19 @@ public class DatabaseEndpoint {
}) })
public ResponseEntity<DatabaseDto> create(@Valid @RequestBody DatabaseCreateDto data, public ResponseEntity<DatabaseDto> create(@Valid @RequestBody DatabaseCreateDto data,
@NotNull Principal principal) throws DataServiceException, @NotNull Principal principal) throws DataServiceException,
DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, ContainerNotFoundException, DataServiceConnectionException, UserNotFoundException, DatabaseNotFoundException,
SearchServiceException, SearchServiceConnectionException, ContainerQuotaException { ContainerNotFoundException, SearchServiceException, SearchServiceConnectionException,
ContainerQuotaException {
log.debug("endpoint create database, data.name={}", data.getName()); log.debug("endpoint create database, data.name={}", data.getName());
final Container container = containerService.find(data.getCid()); final Container container = containerService.find(data.getCid());
final User caller = userService.findByUsername(principal.getName());
if (container.getDatabases().size() + 1 > container.getQuota()) { if (container.getDatabases().size() + 1 > container.getQuota()) {
log.error("Failed to create database: quota of {} exceeded", container.getQuota()); log.error("Failed to create database: quota of {} exceeded", container.getQuota());
throw new ContainerQuotaException("Failed to create database: quota of " + container.getQuota() + " exceeded"); throw new ContainerQuotaException("Failed to create database: quota of " + container.getQuota() + " exceeded");
} }
final User user = userService.findByUsername(principal.getName()); final User caller = userService.findById(getId(principal));
final Database database = databaseService.create(container, data, user);
final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(database, caller);
return ResponseEntity.status(HttpStatus.CREATED) return ResponseEntity.status(HttpStatus.CREATED)
.body(dto); .body(databaseMapper.customDatabaseToDatabaseDto(
databaseService.create(container, data, caller)));
} }
@PutMapping("/{databaseId}/metadata/table") @PutMapping("/{databaseId}/metadata/table")
...@@ -212,13 +217,12 @@ public class DatabaseEndpoint { ...@@ -212,13 +217,12 @@ public class DatabaseEndpoint {
TableNotFoundException { TableNotFoundException {
log.debug("endpoint refresh database metadata, databaseId={}", databaseId); log.debug("endpoint refresh database metadata, databaseId={}", databaseId);
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final User caller = userService.findByUsername(principal.getName()); if (!database.getOwner().getId().equals(getId(principal))) {
if (!database.getOwner().getId().equals(caller.getId())) {
log.error("Failed to refresh database tables metadata: not owner"); log.error("Failed to refresh database tables metadata: not owner");
throw new NotAllowedException("Failed to refresh tables metadata: not owner"); throw new NotAllowedException("Failed to refresh tables metadata: not owner");
} }
final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(databaseService.updateTableMetadata(database), caller); return ResponseEntity.ok(databaseMapper.customDatabaseToDatabaseDto(
return ResponseEntity.ok(dto); databaseService.updateTableMetadata(database)));
} }
@PutMapping("/{databaseId}/metadata/view") @PutMapping("/{databaseId}/metadata/view")
...@@ -261,13 +265,12 @@ public class DatabaseEndpoint { ...@@ -261,13 +265,12 @@ public class DatabaseEndpoint {
SearchServiceConnectionException, NotAllowedException, QueryNotFoundException, ViewNotFoundException { SearchServiceConnectionException, NotAllowedException, QueryNotFoundException, ViewNotFoundException {
log.debug("endpoint refresh database metadata, databaseId={}, principal.name={}", databaseId, principal.getName()); log.debug("endpoint refresh database metadata, databaseId={}, principal.name={}", databaseId, principal.getName());
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final User caller = userService.findByUsername(principal.getName()); if (!database.getOwner().getId().equals(getId(principal))) {
if (!database.getOwner().getId().equals(caller.getId())) {
log.error("Failed to refresh database views metadata: not owner"); log.error("Failed to refresh database views metadata: not owner");
throw new NotAllowedException("Failed to refresh database views metadata: not owner"); throw new NotAllowedException("Failed to refresh database views metadata: not owner");
} }
final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(databaseService.updateViewMetadata(database), caller); return ResponseEntity.ok(databaseMapper.customDatabaseToDatabaseDto(
return ResponseEntity.ok(dto); databaseService.updateViewMetadata(database)));
} }
@PutMapping("/{databaseId}/visibility") @PutMapping("/{databaseId}/visibility")
...@@ -315,14 +318,13 @@ public class DatabaseEndpoint { ...@@ -315,14 +318,13 @@ public class DatabaseEndpoint {
NotAllowedException, SearchServiceException, SearchServiceConnectionException, UserNotFoundException { NotAllowedException, SearchServiceException, SearchServiceConnectionException, UserNotFoundException {
log.debug("endpoint modify database visibility, databaseId={}, data={}", databaseId, data); log.debug("endpoint modify database visibility, databaseId={}, data={}", databaseId, data);
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final User caller = userService.findByUsername(principal.getName()); if (!database.getOwner().getId().equals(getId(principal))) {
if (!database.getOwner().equals(caller)) {
log.error("Failed to modify database visibility: not owner"); log.error("Failed to modify database visibility: not owner");
throw new NotAllowedException("Failed to modify database visibility: not owner"); throw new NotAllowedException("Failed to modify database visibility: not owner");
} }
final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(databaseService.modifyVisibility(database, data), caller);
return ResponseEntity.accepted() return ResponseEntity.accepted()
.body(dto); .body(databaseMapper.customDatabaseToDatabaseDto(
databaseService.modifyVisibility(database, data)));
} }
@PutMapping("/{databaseId}/owner") @PutMapping("/{databaseId}/owner")
...@@ -371,15 +373,14 @@ public class DatabaseEndpoint { ...@@ -371,15 +373,14 @@ public class DatabaseEndpoint {
SearchServiceException, SearchServiceConnectionException { SearchServiceException, SearchServiceConnectionException {
log.debug("endpoint transfer database, databaseId={}, transferDto.id={}", databaseId, data.getId()); log.debug("endpoint transfer database, databaseId={}, transferDto.id={}", databaseId, data.getId());
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final User caller = userService.findByUsername(principal.getName());
final User newOwner = userService.findById(data.getId()); final User newOwner = userService.findById(data.getId());
if (!database.getOwner().equals(caller)) { if (!database.getOwner().getId().equals(getId(principal))) {
log.error("Failed to transfer database: not owner"); log.error("Failed to transfer database: not owner");
throw new NotAllowedException("Failed to transfer database: not owner"); throw new NotAllowedException("Failed to transfer database: not owner");
} }
final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(databaseService.modifyOwner(database, newOwner), caller);
return ResponseEntity.accepted() return ResponseEntity.accepted()
.body(dto); .body(databaseMapper.customDatabaseToDatabaseDto(
databaseService.modifyOwner(database, newOwner)));
} }
@PutMapping("/{databaseId}/image") @PutMapping("/{databaseId}/image")
...@@ -395,13 +396,13 @@ public class DatabaseEndpoint { ...@@ -395,13 +396,13 @@ public class DatabaseEndpoint {
content = {@Content( content = {@Content(
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = DatabaseDto.class))}), schema = @Schema(implementation = DatabaseDto.class))}),
@ApiResponse(responseCode = "404", @ApiResponse(responseCode = "403",
description = "Database or user could not be found", description = "Modify of image is not permitted",
content = {@Content( content = {@Content(
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
@ApiResponse(responseCode = "403", @ApiResponse(responseCode = "404",
description = "Modify of image is not permitted", description = "Database could not be found",
content = {@Content( content = {@Content(
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
...@@ -424,23 +425,21 @@ public class DatabaseEndpoint { ...@@ -424,23 +425,21 @@ public class DatabaseEndpoint {
public ResponseEntity<DatabaseDto> modifyImage(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<DatabaseDto> modifyImage(@NotNull @PathVariable("databaseId") Long databaseId,
@Valid @RequestBody DatabaseModifyImageDto data, @Valid @RequestBody DatabaseModifyImageDto data,
@NotNull Principal principal) throws NotAllowedException, @NotNull Principal principal) throws NotAllowedException,
DatabaseNotFoundException, UserNotFoundException, SearchServiceException, SearchServiceConnectionException, DatabaseNotFoundException, SearchServiceException, SearchServiceConnectionException,
StorageUnavailableException, StorageNotFoundException { StorageUnavailableException, StorageNotFoundException {
log.debug("endpoint modify database image, databaseId={}, data.key={}", databaseId, data.getKey()); log.debug("endpoint modify database image, databaseId={}, data.key={}", databaseId, data.getKey());
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final User caller = userService.findByUsername(principal.getName()); if (!database.getOwner().getId().equals(getId(principal))) {
if (!database.getOwner().getId().equals(caller.getId())) {
log.error("Failed to update database image: not owner"); log.error("Failed to update database image: not owner");
throw new NotAllowedException("Failed to update database image: not owner"); throw new NotAllowedException("Failed to update database image: not owner");
} }
final DatabaseDto dto;
byte[] image = null; byte[] image = null;
if (data.getKey() != null) { if (data.getKey() != null) {
image = storageService.getBytes(data.getKey()); image = storageService.getBytes(data.getKey());
} }
dto = databaseMapper.customDatabaseToDatabaseDto(databaseService.modifyImage(database, image), caller);
return ResponseEntity.accepted() return ResponseEntity.accepted()
.body(dto); .body(databaseMapper.customDatabaseToDatabaseDto(
databaseService.modifyImage(database, image)));
} }
@GetMapping("/{databaseId}/image") @GetMapping("/{databaseId}/image")
...@@ -461,10 +460,9 @@ public class DatabaseEndpoint { ...@@ -461,10 +460,9 @@ public class DatabaseEndpoint {
public ResponseEntity<byte[]> findPreviewImage(@NotNull @PathVariable("databaseId") Long databaseId) public ResponseEntity<byte[]> findPreviewImage(@NotNull @PathVariable("databaseId") Long databaseId)
throws DatabaseNotFoundException { throws DatabaseNotFoundException {
log.debug("endpoint get database preview image, databaseId={}", databaseId); log.debug("endpoint get database preview image, databaseId={}", databaseId);
final Database database = databaseService.findById(databaseId);
return ResponseEntity.ok() return ResponseEntity.ok()
.contentType(MediaType.parseMediaType("image/webp")) .contentType(MediaType.parseMediaType("image/webp"))
.body(database.getImage()); .body(databaseService.findById(databaseId).getImage());
} }
@GetMapping("/{databaseId}") @GetMapping("/{databaseId}")
...@@ -482,6 +480,11 @@ public class DatabaseEndpoint { ...@@ -482,6 +480,11 @@ public class DatabaseEndpoint {
content = {@Content( content = {@Content(
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = DatabaseDto.class))}), schema = @Schema(implementation = DatabaseDto.class))}),
@ApiResponse(responseCode = "403",
description = "Not allowed to view database",
content = {@Content(
mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}),
@ApiResponse(responseCode = "404", @ApiResponse(responseCode = "404",
description = "Database, user or exchange could not be found", description = "Database, user or exchange could not be found",
content = {@Content( content = {@Content(
...@@ -500,27 +503,50 @@ public class DatabaseEndpoint { ...@@ -500,27 +503,50 @@ public class DatabaseEndpoint {
}) })
public ResponseEntity<DatabaseDto> findById(@NotNull @PathVariable("databaseId") Long databaseId, public ResponseEntity<DatabaseDto> findById(@NotNull @PathVariable("databaseId") Long databaseId,
Principal principal) throws DataServiceException, Principal principal) throws DataServiceException,
DataServiceConnectionException, DatabaseNotFoundException, ExchangeNotFoundException, UserNotFoundException { DataServiceConnectionException, DatabaseNotFoundException, ExchangeNotFoundException, UserNotFoundException,
NotAllowedException {
log.debug("endpoint find database, databaseId={}", databaseId); log.debug("endpoint find database, databaseId={}", databaseId);
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final User caller;
if (principal != null) { if (principal != null) {
caller = userService.findByUsername(principal.getName()); final Optional<DatabaseAccess> optional = database.getAccesses()
.stream()
.filter(a -> a.getUser().getId().equals(getId(principal)))
.findFirst();
if (!database.getIsPublic() && !database.getIsSchemaPublic() && optional.isEmpty() && !isSystem(principal)) {
log.error("Failed to find database: not public and no access found");
throw new DatabaseNotFoundException("Failed to find database: not public and no access found");
}
/* reduce metadata */
database.setTables(database.getTables()
.stream()
.filter(t -> t.getIsPublic() || t.getIsSchemaPublic() || optional.isPresent())
.toList());
database.setViews(database.getViews()
.stream()
.filter(v -> v.getIsPublic() || v.getIsSchemaPublic() || optional.isPresent())
.toList());
if (!database.getOwner().getId().equals(getId(principal))) {
database.setAccesses(List.of());
}
} else { } else {
caller = null; if (!database.getIsPublic() && !database.getIsSchemaPublic()) {
log.error("Failed to find database: not public and not authenticated");
throw new NotAllowedException("Failed to find database: not public and not authenticated");
} }
final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(database, caller); /* reduce metadata */
if (caller != null && database.getOwner().getId().equals(caller.getId())) { database.setTables(database.getTables()
log.debug("current logged-in user is also the owner: additionally load access list"); .stream()
/* only owner sees the access rights */ .filter(t -> t.getIsPublic() || t.getIsSchemaPublic())
final List<DatabaseAccess> accesses = accessService.list(database); .toList());
dto.setAccesses(accesses.stream() database.setViews(database.getViews()
.map(databaseMapper::databaseAccessToDatabaseAccessDto) .stream()
.collect(Collectors.toList())); .filter(v -> v.getIsPublic() || v.getIsSchemaPublic())
log.debug("found {} database accesses", accesses.size()); .toList());
database.setAccesses(List.of());
} }
final DatabaseDto dto = databaseMapper.customDatabaseToDatabaseDto(database);
final HttpHeaders headers = new HttpHeaders(); final HttpHeaders headers = new HttpHeaders();
if (UserUtil.isSystem(principal)) { if (isSystem(principal)) {
headers.set("X-Username", database.getContainer().getPrivilegedUsername()); headers.set("X-Username", database.getContainer().getPrivilegedUsername());
headers.set("X-Password", database.getContainer().getPrivilegedPassword()); headers.set("X-Password", database.getContainer().getPrivilegedPassword());
headers.set("X-Host", database.getContainer().getHost()); headers.set("X-Host", database.getContainer().getHost());
......
...@@ -12,10 +12,8 @@ import at.tuwien.entities.identifier.IdentifierStatusType; ...@@ -12,10 +12,8 @@ import at.tuwien.entities.identifier.IdentifierStatusType;
import at.tuwien.entities.identifier.IdentifierType; import at.tuwien.entities.identifier.IdentifierType;
import at.tuwien.entities.user.User; import at.tuwien.entities.user.User;
import at.tuwien.exception.*; import at.tuwien.exception.*;
import at.tuwien.gateway.DataServiceGateway;
import at.tuwien.mapper.MetadataMapper; import at.tuwien.mapper.MetadataMapper;
import at.tuwien.service.*; import at.tuwien.service.*;
import at.tuwien.utils.UserUtil;
import at.tuwien.validation.EndpointValidator; import at.tuwien.validation.EndpointValidator;
import io.micrometer.observation.annotation.Observed; import io.micrometer.observation.annotation.Observed;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
...@@ -29,7 +27,6 @@ import jakarta.validation.Valid; ...@@ -29,7 +27,6 @@ import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
...@@ -48,11 +45,9 @@ import java.util.regex.Pattern; ...@@ -48,11 +45,9 @@ import java.util.regex.Pattern;
@CrossOrigin(origins = "*") @CrossOrigin(origins = "*")
@RestController @RestController
@RequestMapping(path = "/api/identifier") @RequestMapping(path = "/api/identifier")
public class IdentifierEndpoint { public class IdentifierEndpoint extends AbstractEndpoint {
private final UserService userService; private final UserService userService;
private final ViewService viewService;
private final TableService tableService;
private final AccessService accessService; private final AccessService accessService;
private final EndpointConfig endpointConfig; private final EndpointConfig endpointConfig;
private final MetadataMapper metadataMapper; private final MetadataMapper metadataMapper;
...@@ -60,17 +55,15 @@ public class IdentifierEndpoint { ...@@ -60,17 +55,15 @@ public class IdentifierEndpoint {
private final MetadataService metadataService; private final MetadataService metadataService;
private final EndpointValidator endpointValidator; private final EndpointValidator endpointValidator;
private final IdentifierService identifierService; private final IdentifierService identifierService;
private final DataServiceGateway dataServiceGateway;
private static final String CREATE_FOREIGN_IDENTIFIER_ROLE = "create-foreign-identifier";
@Autowired @Autowired
public IdentifierEndpoint(UserService userService, ViewService viewService, TableService tableService, public IdentifierEndpoint(UserService userService, AccessService accessService, EndpointConfig endpointConfig,
AccessService accessService, EndpointConfig endpointConfig, MetadataMapper metadataMapper, MetadataMapper metadataMapper, DatabaseService databaseService,
DatabaseService databaseService, MetadataService metadataService, MetadataService metadataService, EndpointValidator endpointValidator,
EndpointValidator endpointValidator, IdentifierService identifierService, IdentifierService identifierService) {
DataServiceGateway dataServiceGateway) {
this.userService = userService; this.userService = userService;
this.viewService = viewService;
this.tableService = tableService;
this.accessService = accessService; this.accessService = accessService;
this.endpointConfig = endpointConfig; this.endpointConfig = endpointConfig;
this.metadataMapper = metadataMapper; this.metadataMapper = metadataMapper;
...@@ -78,7 +71,6 @@ public class IdentifierEndpoint { ...@@ -78,7 +71,6 @@ public class IdentifierEndpoint {
this.metadataService = metadataService; this.metadataService = metadataService;
this.endpointValidator = endpointValidator; this.endpointValidator = endpointValidator;
this.identifierService = identifierService; this.identifierService = identifierService;
this.dataServiceGateway = dataServiceGateway;
} }
@GetMapping(produces = {MediaType.APPLICATION_JSON_VALUE, "application/ld+json"}) @GetMapping(produces = {MediaType.APPLICATION_JSON_VALUE, "application/ld+json"})
...@@ -119,25 +111,24 @@ public class IdentifierEndpoint { ...@@ -119,25 +111,24 @@ public class IdentifierEndpoint {
return ResponseEntity.ok(List.of()); return ResponseEntity.ok(List.of());
} }
log.trace("found persistent identifiers {}", identifiers); log.trace("found persistent identifiers {}", identifiers);
switch (accept) { return switch (accept) {
case "application/json": case "application/json" -> {
log.trace("accept header matches json"); log.trace("accept header matches json");
final List<IdentifierBriefDto> resource1 = identifiers.stream() yield ResponseEntity.ok(identifiers.stream()
.map(metadataMapper::identifierToIdentifierBriefDto) .map(metadataMapper::identifierToIdentifierBriefDto)
.toList(); .toList());
log.debug("find identifier resulted in identifiers {}", resource1); }
return ResponseEntity.ok(resource1); case "application/ld+json" -> {
case "application/ld+json":
log.trace("accept header matches json-ld"); log.trace("accept header matches json-ld");
final List<LdDatasetDto> resource2 = identifiers.stream() yield ResponseEntity.ok(identifiers.stream()
.map(i -> metadataMapper.identifierToLdDatasetDto(i, endpointConfig.getWebsiteUrl())) .map(i -> metadataMapper.identifierToLdDatasetDto(i, endpointConfig.getWebsiteUrl()))
.toList(); .toList());
log.debug("find identifier resulted in identifiers {}", resource2); }
return ResponseEntity.ok(resource2); default -> {
default:
log.error("accept header {} is not supported", accept); log.error("accept header {} is not supported", accept);
throw new FormatNotAvailableException("Must provide either application/json or application/ld+json headers"); throw new FormatNotAvailableException("Must provide either application/json or application/ld+json headers");
} }
};
} }
@GetMapping(value = "/{identifierId}", produces = {MediaType.APPLICATION_JSON_VALUE, "application/ld+json", @GetMapping(value = "/{identifierId}", produces = {MediaType.APPLICATION_JSON_VALUE, "application/ld+json",
...@@ -209,30 +200,20 @@ public class IdentifierEndpoint { ...@@ -209,30 +200,20 @@ public class IdentifierEndpoint {
switch (accept) { switch (accept) {
case "application/json": case "application/json":
log.trace("accept header matches json"); log.trace("accept header matches json");
final IdentifierDto resource1 = metadataMapper.identifierToIdentifierDto(identifier); return ResponseEntity.ok(metadataMapper.identifierToIdentifierDto(identifier));
log.debug("find identifier resulted in identifier {}", resource1);
return ResponseEntity.ok(resource1);
case "application/ld+json": case "application/ld+json":
log.trace("accept header matches json-ld"); log.trace("accept header matches json-ld");
final LdDatasetDto resource2 = metadataMapper.identifierToLdDatasetDto(identifier, endpointConfig.getWebsiteUrl()); return ResponseEntity.ok(metadataMapper.identifierToLdDatasetDto(identifier, endpointConfig.getWebsiteUrl()));
log.debug("find identifier resulted in identifier {}", resource2);
log.debug("find identifier resulted in identifier {}", resource2);
return ResponseEntity.ok(resource2);
case "text/csv": case "text/csv":
log.trace("accept header matches csv"); log.trace("accept header matches csv");
if (identifier.getType().equals(IdentifierType.DATABASE)) { if (identifier.getType().equals(IdentifierType.DATABASE)) {
log.error("Failed to export dataset: identifier type is database"); log.error("Failed to export dataset: identifier type is database");
throw new FormatNotAvailableException("Failed to export dataset: identifier type is database"); throw new FormatNotAvailableException("Failed to export dataset: identifier type is database");
} }
final InputStreamResource resource3; return ResponseEntity.ok(identifierService.exportResource(identifier));
resource3 = identifierService.exportResource(identifier);
log.debug("find identifier resulted in resource {}", resource3);
return ResponseEntity.ok(resource3);
case "text/xml": case "text/xml":
log.trace("accept header matches xml"); log.trace("accept header matches xml");
final InputStreamResource resource4 = identifierService.exportMetadata(identifier); return ResponseEntity.ok(identifierService.exportMetadata(identifier));
log.debug("find identifier resulted in resource {}", resource4);
return ResponseEntity.ok(resource4);
} }
final Pattern regex = Pattern.compile("text\\/bibliography(; ?style=(apa|ieee|bibtex))?"); final Pattern regex = Pattern.compile("text\\/bibliography(; ?style=(apa|ieee|bibtex))?");
final Matcher matcher = regex.matcher(accept); final Matcher matcher = regex.matcher(accept);
...@@ -348,9 +329,9 @@ public class IdentifierEndpoint { ...@@ -348,9 +329,9 @@ public class IdentifierEndpoint {
throws SearchServiceException, DatabaseNotFoundException, SearchServiceConnectionException, throws SearchServiceException, DatabaseNotFoundException, SearchServiceConnectionException,
MalformedException, DataServiceConnectionException, IdentifierNotFoundException, ExternalServiceException { MalformedException, DataServiceConnectionException, IdentifierNotFoundException, ExternalServiceException {
log.debug("endpoint publish identifier, identifierId={}", identifierId); log.debug("endpoint publish identifier, identifierId={}", identifierId);
final Identifier identifier = identifierService.find(identifierId);
return ResponseEntity.status(HttpStatus.CREATED) return ResponseEntity.status(HttpStatus.CREATED)
.body(metadataMapper.identifierToIdentifierDto(identifierService.publish(identifier))); .body(metadataMapper.identifierToIdentifierDto(
identifierService.publish(identifierService.find(identifierId))));
} }
@PutMapping("/{identifierId}") @PutMapping("/{identifierId}")
...@@ -402,10 +383,10 @@ public class IdentifierEndpoint { ...@@ -402,10 +383,10 @@ public class IdentifierEndpoint {
log.debug("endpoint save identifier, identifierId={}, data.id={}, principal.name={}", identifierId, log.debug("endpoint save identifier, identifierId={}, data.id={}, principal.name={}", identifierId,
data.getId(), principal.getName()); data.getId(), principal.getName());
final Database database = databaseService.findById(data.getDatabaseId()); final Database database = databaseService.findById(data.getDatabaseId());
final User caller = userService.findByUsername(principal.getName()); final User caller = userService.findById(getId(principal));
final Identifier identifier = identifierService.find(identifierId); final Identifier identifier = identifierService.find(identifierId);
/* check owner */ /* check owner */
if (!identifier.getOwner().getId().equals(caller.getId()) && !UserUtil.hasRole(principal, "create-foreign-identifier")) { if (!identifier.getOwner().getId().equals(getId(principal)) && !hasRole(principal, CREATE_FOREIGN_IDENTIFIER_ROLE)) {
log.error("Failed to save identifier: foreign user"); log.error("Failed to save identifier: foreign user");
throw new NotAllowedException("Failed to save identifier: foreign user"); throw new NotAllowedException("Failed to save identifier: foreign user");
} }
...@@ -419,7 +400,7 @@ public class IdentifierEndpoint { ...@@ -419,7 +400,7 @@ public class IdentifierEndpoint {
final DatabaseAccess access = accessService.find(database, caller); final DatabaseAccess access = accessService.find(database, caller);
log.trace("found access: {}", access); log.trace("found access: {}", access);
} catch (AccessNotFoundException e) { } catch (AccessNotFoundException e) {
if (!UserUtil.hasRole(principal, "create-foreign-identifier")) { if (!hasRole(principal, CREATE_FOREIGN_IDENTIFIER_ROLE)) {
log.error("Failed to save identifier: insufficient role"); log.error("Failed to save identifier: insufficient role");
throw new NotAllowedException("Failed to save identifier: insufficient role"); throw new NotAllowedException("Failed to save identifier: insufficient role");
} }
...@@ -501,12 +482,12 @@ public class IdentifierEndpoint { ...@@ -501,12 +482,12 @@ public class IdentifierEndpoint {
IdentifierNotFoundException, ViewNotFoundException, ExternalServiceException { IdentifierNotFoundException, ViewNotFoundException, ExternalServiceException {
log.debug("endpoint create identifier, data.databaseId={}", data.getDatabaseId()); log.debug("endpoint create identifier, data.databaseId={}", data.getDatabaseId());
final Database database = databaseService.findById(data.getDatabaseId()); final Database database = databaseService.findById(data.getDatabaseId());
final User caller = userService.findByUsername(principal.getName()); final User caller = userService.findById(getId(principal));
/* check access */ /* check access */
try { try {
accessService.find(database, caller); accessService.find(database, caller);
} catch (AccessNotFoundException e) { } catch (AccessNotFoundException e) {
if (!UserUtil.hasRole(principal, "create-foreign-identifier")) { if (!hasRole(principal, CREATE_FOREIGN_IDENTIFIER_ROLE)) {
log.error("Failed to create identifier: insufficient role"); log.error("Failed to create identifier: insufficient role");
throw new NotAllowedException("Failed to create identifier: insufficient role"); throw new NotAllowedException("Failed to create identifier: insufficient role");
} }
...@@ -532,8 +513,9 @@ public class IdentifierEndpoint { ...@@ -532,8 +513,9 @@ public class IdentifierEndpoint {
mediaType = "application/json", mediaType = "application/json",
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<ExternalMetadataDto> retrieve(@NotNull @Valid @RequestParam String url) public ResponseEntity<ExternalMetadataDto> retrieve(@NotNull @Valid @RequestParam("url") String url)
throws OrcidNotFoundException, RorNotFoundException, DoiNotFoundException, IdentifierNotSupportedException { throws OrcidNotFoundException, RorNotFoundException, DoiNotFoundException, IdentifierNotSupportedException {
log.debug("endpoint retrieve identifier, url={}", url);
return ResponseEntity.ok(metadataService.findByUrl(url)); return ResponseEntity.ok(metadataService.findByUrl(url));
} }
......
...@@ -37,7 +37,7 @@ import java.util.List; ...@@ -37,7 +37,7 @@ import java.util.List;
@CrossOrigin(origins = "*") @CrossOrigin(origins = "*")
@ControllerAdvice @ControllerAdvice
@RequestMapping(path = "/api/image") @RequestMapping(path = "/api/image")
public class ImageEndpoint { public class ImageEndpoint extends AbstractEndpoint {
private final MetadataMapper metadataMapper; private final MetadataMapper metadataMapper;
private final ImageServiceImpl imageService; private final ImageServiceImpl imageService;
...@@ -97,11 +97,9 @@ public class ImageEndpoint { ...@@ -97,11 +97,9 @@ public class ImageEndpoint {
@NotNull Principal principal) throws ImageAlreadyExistsException, @NotNull Principal principal) throws ImageAlreadyExistsException,
ImageInvalidException { ImageInvalidException {
log.debug("endpoint create image, data={}, principal.name={}", data, principal.getName()); log.debug("endpoint create image, data={}, principal.name={}", data, principal.getName());
final ContainerImage image = imageService.create(data, principal);
final ImageDto dto = metadataMapper.containerImageToImageDto(image);
log.trace("create image resulted in image {}", dto);
return ResponseEntity.status(HttpStatus.CREATED) return ResponseEntity.status(HttpStatus.CREATED)
.body(dto); .body(metadataMapper.containerImageToImageDto(
imageService.create(data, principal)));
} }
@GetMapping("/{imageId}") @GetMapping("/{imageId}")
...@@ -122,12 +120,9 @@ public class ImageEndpoint { ...@@ -122,12 +120,9 @@ public class ImageEndpoint {
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<ImageDto> findById(@NotNull @PathVariable("imageId") Long imageId) throws ImageNotFoundException { public ResponseEntity<ImageDto> findById(@NotNull @PathVariable("imageId") Long imageId) throws ImageNotFoundException {
log.debug("endpoint find image, id={}", imageId); log.debug("endpoint find image, imageId={}", imageId);
final ContainerImage image = imageService.find(imageId);
final ImageDto dto = metadataMapper.containerImageToImageDto(image);
log.trace("find image resulted in image {}", dto);
return ResponseEntity.ok() return ResponseEntity.ok()
.body(dto); .body(metadataMapper.containerImageToImageDto(imageService.find(imageId)));
} }
@PutMapping("/{imageId}") @PutMapping("/{imageId}")
...@@ -152,13 +147,10 @@ public class ImageEndpoint { ...@@ -152,13 +147,10 @@ public class ImageEndpoint {
public ResponseEntity<ImageDto> update(@NotNull @PathVariable("imageId") Long imageId, public ResponseEntity<ImageDto> update(@NotNull @PathVariable("imageId") Long imageId,
@RequestBody @Valid ImageChangeDto changeDto) @RequestBody @Valid ImageChangeDto changeDto)
throws ImageNotFoundException { throws ImageNotFoundException {
log.debug("endpoint update image, id={}, changeDto={}", imageId, changeDto); log.debug("endpoint update image, imageId={}, changeDto={}", imageId, changeDto);
ContainerImage image = imageService.find(imageId);
image = imageService.update(image, changeDto);
final ImageDto dto = metadataMapper.containerImageToImageDto(image);
log.trace("update image resulted in image {}", dto);
return ResponseEntity.accepted() return ResponseEntity.accepted()
.body(dto); .body(metadataMapper.containerImageToImageDto(
imageService.update(imageService.find(imageId), changeDto)));
} }
@DeleteMapping("/{imageId}") @DeleteMapping("/{imageId}")
...@@ -179,9 +171,8 @@ public class ImageEndpoint { ...@@ -179,9 +171,8 @@ public class ImageEndpoint {
schema = @Schema(implementation = ApiErrorDto.class))}), schema = @Schema(implementation = ApiErrorDto.class))}),
}) })
public ResponseEntity<Void> delete(@NotNull @PathVariable("imageId") Long imageId) throws ImageNotFoundException { public ResponseEntity<Void> delete(@NotNull @PathVariable("imageId") Long imageId) throws ImageNotFoundException {
log.debug("endpoint delete image, id={}", imageId); log.debug("endpoint delete image, imageId={}", imageId);
final ContainerImage image = imageService.find(imageId); imageService.delete(imageService.find(imageId));
imageService.delete(image);
return ResponseEntity.accepted() return ResponseEntity.accepted()
.build(); .build();
} }
......
...@@ -21,7 +21,6 @@ import org.springframework.web.bind.annotation.RequestMapping; ...@@ -21,7 +21,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
@Log4j2 @Log4j2
@RestController @RestController
...@@ -52,12 +51,11 @@ public class LicenseEndpoint { ...@@ -52,12 +51,11 @@ public class LicenseEndpoint {
}) })
public ResponseEntity<List<LicenseDto>> list() { public ResponseEntity<List<LicenseDto>> list() {
log.debug("endpoint list licenses"); log.debug("endpoint list licenses");
final List<LicenseDto> licenses = licenseService.findAll() return ResponseEntity.status(HttpStatus.OK)
.body(licenseService.findAll()
.stream() .stream()
.map(metadataMapper::licenseToLicenseDto) .map(metadataMapper::licenseToLicenseDto)
.toList(); .toList());
return ResponseEntity.status(HttpStatus.OK)
.body(licenses);
} }
} }
...@@ -56,20 +56,15 @@ public class MessageEndpoint { ...@@ -56,20 +56,15 @@ public class MessageEndpoint {
}) })
public ResponseEntity<List<BannerMessageDto>> list(@RequestParam(required = false) Boolean active) { public ResponseEntity<List<BannerMessageDto>> list(@RequestParam(required = false) Boolean active) {
log.debug("endpoint list messages, active={}", active); log.debug("endpoint list messages, active={}", active);
List<BannerMessageDto> dtos; final List<BannerMessage> messages;
if (active != null && active) { if (active != null && active) {
dtos = bannerMessageService.getActive() messages = bannerMessageService.getActive();
.stream()
.map(metadataMapper::bannerMessageToBannerMessageDto)
.toList();
} else { } else {
dtos = bannerMessageService.findAll() messages = bannerMessageService.findAll();
.stream()
.map(metadataMapper::bannerMessageToBannerMessageDto)
.toList();
} }
log.info("List messages resulted in {} message(s)", dtos.size()); return ResponseEntity.ok(messages.stream()
return ResponseEntity.ok(dtos); .map(metadataMapper::bannerMessageToBannerMessageDto)
.toList());
} }
@GetMapping("/message/{messageId}") @GetMapping("/message/{messageId}")
...@@ -91,8 +86,8 @@ public class MessageEndpoint { ...@@ -91,8 +86,8 @@ public class MessageEndpoint {
public ResponseEntity<BannerMessageDto> find(@NotNull @PathVariable("messageId") Long messageId) public ResponseEntity<BannerMessageDto> find(@NotNull @PathVariable("messageId") Long messageId)
throws MessageNotFoundException { throws MessageNotFoundException {
log.debug("endpoint find one maintenance message, messageId={}", messageId); log.debug("endpoint find one maintenance message, messageId={}", messageId);
final BannerMessageDto dto = metadataMapper.bannerMessageToBannerMessageDto(bannerMessageService.find(messageId)); return ResponseEntity.ok(metadataMapper.bannerMessageToBannerMessageDto(
return ResponseEntity.ok(dto); bannerMessageService.find(messageId)));
} }
@PostMapping @PostMapping
...@@ -110,10 +105,9 @@ public class MessageEndpoint { ...@@ -110,10 +105,9 @@ public class MessageEndpoint {
}) })
public ResponseEntity<BannerMessageDto> create(@Valid @RequestBody BannerMessageCreateDto data) { public ResponseEntity<BannerMessageDto> create(@Valid @RequestBody BannerMessageCreateDto data) {
log.debug("endpoint create maintenance message, data={}", data); log.debug("endpoint create maintenance message, data={}", data);
final BannerMessageDto dto = metadataMapper.bannerMessageToBannerMessageDto(bannerMessageService.create(data));
log.trace("create maintenance message results in dto {}", dto);
return ResponseEntity.status(HttpStatus.CREATED) return ResponseEntity.status(HttpStatus.CREATED)
.body(dto); .body(metadataMapper.bannerMessageToBannerMessageDto(
bannerMessageService.create(data)));
} }
@PutMapping("/{messageId}") @PutMapping("/{messageId}")
...@@ -139,10 +133,9 @@ public class MessageEndpoint { ...@@ -139,10 +133,9 @@ public class MessageEndpoint {
throws MessageNotFoundException { throws MessageNotFoundException {
log.debug("endpoint update maintenance message, messageId={}, data={}", messageId, data); log.debug("endpoint update maintenance message, messageId={}, data={}", messageId, data);
final BannerMessage message = bannerMessageService.find(messageId); final BannerMessage message = bannerMessageService.find(messageId);
final BannerMessageDto dto = metadataMapper.bannerMessageToBannerMessageDto(bannerMessageService.update(message, data)); return ResponseEntity.accepted()
log.trace("update maintenance message results in dto {}", dto); .body(metadataMapper.bannerMessageToBannerMessageDto(
return ResponseEntity.status(HttpStatus.ACCEPTED) bannerMessageService.update(message, data)));
.body(dto);
} }
@DeleteMapping("/{messageId}") @DeleteMapping("/{messageId}")
...@@ -166,7 +159,7 @@ public class MessageEndpoint { ...@@ -166,7 +159,7 @@ public class MessageEndpoint {
log.debug("endpoint delete maintenance message, messageId={}", messageId); log.debug("endpoint delete maintenance message, messageId={}", messageId);
final BannerMessage message = bannerMessageService.find(messageId); final BannerMessage message = bannerMessageService.find(messageId);
bannerMessageService.delete(message); bannerMessageService.delete(message);
return ResponseEntity.status(HttpStatus.ACCEPTED) return ResponseEntity.accepted()
.build(); .build();
} }
......
...@@ -29,7 +29,7 @@ import java.util.List; ...@@ -29,7 +29,7 @@ import java.util.List;
@CrossOrigin(origins = "*") @CrossOrigin(origins = "*")
@RestController @RestController
@RequestMapping(path = "/api/oai") @RequestMapping(path = "/api/oai")
public class MetadataEndpoint { public class MetadataEndpoint extends AbstractEndpoint {
private final MetadataService metadataService; private final MetadataService metadataService;
......
...@@ -3,9 +3,11 @@ package at.tuwien.endpoints; ...@@ -3,9 +3,11 @@ package at.tuwien.endpoints;
import at.tuwien.api.error.ApiErrorDto; import at.tuwien.api.error.ApiErrorDto;
import at.tuwien.api.semantics.*; import at.tuwien.api.semantics.*;
import at.tuwien.entities.semantics.Ontology; import at.tuwien.entities.semantics.Ontology;
import at.tuwien.exception.*; import at.tuwien.exception.FilterBadRequestException;
import at.tuwien.exception.MalformedException;
import at.tuwien.exception.OntologyNotFoundException;
import at.tuwien.exception.UriMalformedException;
import at.tuwien.mapper.MetadataMapper; import at.tuwien.mapper.MetadataMapper;
import at.tuwien.mapper.SparqlMapper;
import at.tuwien.service.EntityService; import at.tuwien.service.EntityService;
import at.tuwien.service.OntologyService; import at.tuwien.service.OntologyService;
import io.micrometer.observation.annotation.Observed; import io.micrometer.observation.annotation.Observed;
...@@ -32,7 +34,7 @@ import java.util.List; ...@@ -32,7 +34,7 @@ import java.util.List;
@CrossOrigin(origins = "*") @CrossOrigin(origins = "*")
@RestController @RestController
@RequestMapping(path = "/api/ontology") @RequestMapping(path = "/api/ontology")
public class OntologyEndpoint { public class OntologyEndpoint extends AbstractEndpoint {
private final EntityService entityService; private final EntityService entityService;
private final MetadataMapper metadataMapper; private final MetadataMapper metadataMapper;
...@@ -59,11 +61,10 @@ public class OntologyEndpoint { ...@@ -59,11 +61,10 @@ public class OntologyEndpoint {
}) })
public ResponseEntity<List<OntologyBriefDto>> findAll() { public ResponseEntity<List<OntologyBriefDto>> findAll() {
log.debug("endpoint find all ontologies"); log.debug("endpoint find all ontologies");
final List<OntologyBriefDto> dtos = ontologyService.findAll() return ResponseEntity.ok(ontologyService.findAll()
.stream() .stream()
.map(metadataMapper::ontologyToOntologyBriefDto) .map(metadataMapper::ontologyToOntologyBriefDto)
.toList(); .toList());
return ResponseEntity.ok(dtos);
} }
@GetMapping("/{ontologyId}") @GetMapping("/{ontologyId}")
...@@ -85,8 +86,7 @@ public class OntologyEndpoint { ...@@ -85,8 +86,7 @@ public class OntologyEndpoint {
public ResponseEntity<OntologyDto> find(@NotNull @PathVariable("ontologyId") Long ontologyId) public ResponseEntity<OntologyDto> find(@NotNull @PathVariable("ontologyId") Long ontologyId)
throws OntologyNotFoundException { throws OntologyNotFoundException {
log.debug("endpoint find all ontologies, ontologyId={}", ontologyId); log.debug("endpoint find all ontologies, ontologyId={}", ontologyId);
final OntologyDto dto = metadataMapper.ontologyToOntologyDto(ontologyService.find(ontologyId)); return ResponseEntity.ok(metadataMapper.ontologyToOntologyDto(ontologyService.find(ontologyId)));
return ResponseEntity.ok(dto);
} }
@PostMapping @PostMapping
...@@ -104,10 +104,9 @@ public class OntologyEndpoint { ...@@ -104,10 +104,9 @@ public class OntologyEndpoint {
}) })
public ResponseEntity<OntologyDto> create(@NotNull @Valid @RequestBody OntologyCreateDto data, public ResponseEntity<OntologyDto> create(@NotNull @Valid @RequestBody OntologyCreateDto data,
@NotNull Principal principal) { @NotNull Principal principal) {
log.debug("endpoint create ontology, data={}", data); log.debug("endpoint create ontology, data={}, principal.name={}", data, principal.getName());
final OntologyDto dto = metadataMapper.ontologyToOntologyDto(ontologyService.create(data, principal));
return ResponseEntity.status(HttpStatus.CREATED) return ResponseEntity.status(HttpStatus.CREATED)
.body(dto); .body(metadataMapper.ontologyToOntologyDto(ontologyService.create(data, principal)));
} }
@PutMapping("/{ontologyId}") @PutMapping("/{ontologyId}")
...@@ -131,11 +130,10 @@ public class OntologyEndpoint { ...@@ -131,11 +130,10 @@ public class OntologyEndpoint {
public ResponseEntity<OntologyDto> update(@NotNull @PathVariable("ontologyId") Long ontologyId, public ResponseEntity<OntologyDto> update(@NotNull @PathVariable("ontologyId") Long ontologyId,
@NotNull @Valid @RequestBody OntologyModifyDto data) @NotNull @Valid @RequestBody OntologyModifyDto data)
throws OntologyNotFoundException { throws OntologyNotFoundException {
log.debug("endpoint update ontology, data={}", data); log.debug("endpoint update ontology, ontologyId={}, data={}", ontologyId, data);
final Ontology ontology = ontologyService.find(ontologyId);
final OntologyDto dto = metadataMapper.ontologyToOntologyDto(ontologyService.update(ontology, data));
return ResponseEntity.accepted() return ResponseEntity.accepted()
.body(dto); .body(metadataMapper.ontologyToOntologyDto(
ontologyService.update(ontologyService.find(ontologyId), data)));
} }
@DeleteMapping("/{ontologyId}") @DeleteMapping("/{ontologyId}")
...@@ -158,8 +156,7 @@ public class OntologyEndpoint { ...@@ -158,8 +156,7 @@ public class OntologyEndpoint {
public ResponseEntity<Void> delete(@NotNull @PathVariable("ontologyId") Long ontologyId) public ResponseEntity<Void> delete(@NotNull @PathVariable("ontologyId") Long ontologyId)
throws OntologyNotFoundException { throws OntologyNotFoundException {
log.debug("endpoint delete ontology, ontologyId={}", ontologyId); log.debug("endpoint delete ontology, ontologyId={}", ontologyId);
final Ontology ontology = ontologyService.find(ontologyId); ontologyService.delete(ontologyService.find(ontologyId));
ontologyService.delete(ontology);
return ResponseEntity.accepted() return ResponseEntity.accepted()
.build(); .build();
} }
...@@ -217,15 +214,12 @@ public class OntologyEndpoint { ...@@ -217,15 +214,12 @@ public class OntologyEndpoint {
throw new OntologyNotFoundException("Failed to find SPARQL endpoint for ontology with id " + ontology.getId()); throw new OntologyNotFoundException("Failed to find SPARQL endpoint for ontology with id " + ontology.getId());
} }
/* get */ /* get */
final List<EntityDto> dtos;
if (uri != null) { if (uri != null) {
dtos = entityService.findByUri(uri);
return ResponseEntity.ok() return ResponseEntity.ok()
.body(dtos); .body(entityService.findByUri(uri));
} }
dtos = entityService.findByLabel(ontology, label);
return ResponseEntity.ok() return ResponseEntity.ok()
.body(dtos); .body(entityService.findByLabel(ontology, label));
} }
} }
...@@ -11,12 +11,9 @@ import at.tuwien.api.semantics.EntityDto; ...@@ -11,12 +11,9 @@ import at.tuwien.api.semantics.EntityDto;
import at.tuwien.api.semantics.TableColumnEntityDto; import at.tuwien.api.semantics.TableColumnEntityDto;
import at.tuwien.entities.database.Database; import at.tuwien.entities.database.Database;
import at.tuwien.entities.database.table.Table; import at.tuwien.entities.database.table.Table;
import at.tuwien.entities.database.table.columns.TableColumn;
import at.tuwien.entities.user.User;
import at.tuwien.exception.*; import at.tuwien.exception.*;
import at.tuwien.mapper.MetadataMapper; import at.tuwien.mapper.MetadataMapper;
import at.tuwien.service.*; import at.tuwien.service.*;
import at.tuwien.utils.UserUtil;
import at.tuwien.validation.EndpointValidator; import at.tuwien.validation.EndpointValidator;
import io.micrometer.observation.annotation.Observed; import io.micrometer.observation.annotation.Observed;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
...@@ -46,7 +43,7 @@ import java.util.stream.Collectors; ...@@ -46,7 +43,7 @@ import java.util.stream.Collectors;
@CrossOrigin(origins = "*") @CrossOrigin(origins = "*")
@RestController @RestController
@RequestMapping(path = "/api/database/{databaseId}/table") @RequestMapping(path = "/api/database/{databaseId}/table")
public class TableEndpoint { public class TableEndpoint extends AbstractEndpoint {
private final UserService userService; private final UserService userService;
private final TableService tableService; private final TableService tableService;
...@@ -99,12 +96,10 @@ public class TableEndpoint { ...@@ -99,12 +96,10 @@ public class TableEndpoint {
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
endpointValidator.validateOnlyPrivateAccess(database, principal); endpointValidator.validateOnlyPrivateAccess(database, principal);
endpointValidator.validateOnlyPrivateHasRole(database, principal, "list-tables"); endpointValidator.validateOnlyPrivateHasRole(database, principal, "list-tables");
final List<TableBriefDto> dto = database.getTables() return ResponseEntity.ok(database.getTables()
.stream() .stream()
.map(metadataMapper::tableToTableBriefDto) .map(metadataMapper::tableToTableBriefDto)
.collect(Collectors.toList()); .collect(Collectors.toList()));
log.trace("list tables resulted in tables {}", dto);
return ResponseEntity.ok(dto);
} }
@GetMapping("/{tableId}/suggest") @GetMapping("/{tableId}/suggest")
...@@ -154,7 +149,7 @@ public class TableEndpoint { ...@@ -154,7 +149,7 @@ public class TableEndpoint {
principal); principal);
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final Table table = tableService.findById(database, tableId); final Table table = tableService.findById(database, tableId);
if (!table.getOwner().getUsername().equals(principal.getName())) { if (!table.getOwner().getId().equals(getId(principal))) {
log.error("Failed to analyse table semantics: not owner"); log.error("Failed to analyse table semantics: not owner");
throw new NotAllowedException("Failed to analyse table semantics: not owner"); throw new NotAllowedException("Failed to analyse table semantics: not owner");
} }
...@@ -207,7 +202,7 @@ public class TableEndpoint { ...@@ -207,7 +202,7 @@ public class TableEndpoint {
principal.getName()); principal.getName());
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final Table table = tableService.findById(database, tableId); final Table table = tableService.findById(database, tableId);
if (!table.getOwner().getUsername().equals(principal.getName())) { if (!table.getOwner().getId().equals(getId(principal))) {
log.error("Failed to update table statistics: not owner"); log.error("Failed to update table statistics: not owner");
throw new NotAllowedException("Failed to update table statistics: not owner"); throw new NotAllowedException("Failed to update table statistics: not owner");
} }
...@@ -266,19 +261,14 @@ public class TableEndpoint { ...@@ -266,19 +261,14 @@ public class TableEndpoint {
log.debug("endpoint update table, databaseId={}, tableId={}, columnId={}, principal.name={}", databaseId, log.debug("endpoint update table, databaseId={}, tableId={}, columnId={}, principal.name={}", databaseId,
tableId, columnId, principal.getName()); tableId, columnId, principal.getName());
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final User user = userService.findByUsername(principal.getName());
final Table table = tableService.findById(database, tableId); final Table table = tableService.findById(database, tableId);
if (!UserUtil.hasRole(principal, "modify-foreign-table-column-semantics")) { if (!hasRole(principal, "modify-foreign-table-column-semantics")) {
endpointValidator.validateOnlyAccess(table.getDatabase(), principal, true); endpointValidator.validateOnlyAccess(database, principal, true);
endpointValidator.validateOnlyOwnerOrWriteAll(table, user); endpointValidator.validateOnlyOwnerOrWriteAll(table, userService.findById(getId(principal)));
} }
TableColumn column = tableService.findColumnById(table, columnId);
column = tableService.update(column, updateDto);
log.info("Updated table semantics of table with id {}", tableId);
final ColumnDto columnDto = metadataMapper.tableColumnToColumnDto(column);
log.trace("find table data resulted in column {}", columnDto);
return ResponseEntity.accepted() return ResponseEntity.accepted()
.body(columnDto); .body(metadataMapper.tableColumnToColumnDto(tableService.update(
tableService.findColumnById(table, columnId), updateDto)));
} }
@GetMapping("/{tableId}/column/{columnId}/suggest") @GetMapping("/{tableId}/column/{columnId}/suggest")
...@@ -317,12 +307,10 @@ public class TableEndpoint { ...@@ -317,12 +307,10 @@ public class TableEndpoint {
throws MalformedException, TableNotFoundException, DatabaseNotFoundException { throws MalformedException, TableNotFoundException, DatabaseNotFoundException {
log.debug("endpoint analyse table column semantics, databaseId={}, tableId={}, columnId={}, principal.name={}", log.debug("endpoint analyse table column semantics, databaseId={}, tableId={}, columnId={}, principal.name={}",
databaseId, tableId, columnId, principal.getName()); databaseId, tableId, columnId, principal.getName());
final Database database = databaseService.findById(databaseId);
final Table table = tableService.findById(database, tableId);
TableColumn column = tableService.findColumnById(table, columnId);
final List<TableColumnEntityDto> dtos = entityService.suggestByColumn(column);
return ResponseEntity.ok() return ResponseEntity.ok()
.body(dtos); .body(entityService.suggestByColumn(
tableService.findColumnById(
tableService.findById(databaseService.findById(databaseId), tableId), columnId)));
} }
@PostMapping @PostMapping
...@@ -380,11 +368,9 @@ public class TableEndpoint { ...@@ -380,11 +368,9 @@ public class TableEndpoint {
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
endpointValidator.validateOnlyAccess(database, principal, true); endpointValidator.validateOnlyAccess(database, principal, true);
endpointValidator.validateColumnCreateConstraints(data); endpointValidator.validateColumnCreateConstraints(data);
final Table table = tableService.createTable(database, data, principal);
final TableDto dto = metadataMapper.customTableToTableDto(table);
log.info("Created table with id {}", dto.getId());
return ResponseEntity.status(HttpStatus.CREATED) return ResponseEntity.status(HttpStatus.CREATED)
.body(dto); .body(metadataMapper.customTableToTableDto(
tableService.createTable(database, data, principal)));
} }
@PutMapping("/{tableId}") @PutMapping("/{tableId}")
...@@ -436,14 +422,13 @@ public class TableEndpoint { ...@@ -436,14 +422,13 @@ public class TableEndpoint {
databaseId, data.getIsPublic(), data.getIsSchemaPublic(), principal.getName()); databaseId, data.getIsPublic(), data.getIsSchemaPublic(), principal.getName());
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final Table table = tableService.findById(database, tableId); final Table table = tableService.findById(database, tableId);
if (!table.getOwner().getUsername().equals(principal.getName())) { if (!table.getOwner().getId().equals(getId(principal))) {
log.error("Failed to update table: not owner"); log.error("Failed to update table: not owner");
throw new NotAllowedException("Failed to update table: not owner"); throw new NotAllowedException("Failed to update table: not owner");
} }
final TableDto dto = metadataMapper.customTableToTableDto(tableService.updateTable(table, data)); return ResponseEntity.accepted()
log.info("Updated table with id {}", dto.getId()); .body(metadataMapper.customTableToTableDto(
return ResponseEntity.status(HttpStatus.ACCEPTED) tableService.updateTable(table, data)));
.body(dto);
} }
@GetMapping("/{tableId}") @GetMapping("/{tableId}")
...@@ -494,25 +479,22 @@ public class TableEndpoint { ...@@ -494,25 +479,22 @@ public class TableEndpoint {
log.debug("endpoint find table, databaseId={}, tableId={}", databaseId, tableId); log.debug("endpoint find table, databaseId={}, tableId={}", databaseId, tableId);
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final Table table = tableService.findById(database, tableId); final Table table = tableService.findById(database, tableId);
boolean hasAccess = UserUtil.isSystem(principal); boolean hasAccess = isSystem(principal);
boolean isOwner = false; boolean isOwner = false;
try { try {
if (principal != null) { if (principal != null) {
final User user = userService.findByUsername(principal.getName()); accessService.find(table.getDatabase(), userService.findById(getId(principal)));
accessService.find(table.getDatabase(), user);
hasAccess = true; hasAccess = true;
isOwner = table.getOwner().getId().equals(user.getId()); isOwner = table.getOwner().getId().equals(getId(principal));
} }
} catch (UserNotFoundException | AccessNotFoundException e) { } catch (UserNotFoundException | AccessNotFoundException e) {
/* ignore */ /* ignore */
} }
final boolean includeSchema = UserUtil.isSystem(principal) || isOwner || table.getIsSchemaPublic(); final boolean includeSchema = isSystem(principal) || isOwner || table.getIsSchemaPublic();
log.trace("user has access: {}", hasAccess); log.trace("user has access: {}", hasAccess);
log.trace("include schema in mapping: {}", includeSchema); log.trace("include schema in mapping: {}", includeSchema);
final TableDto dto = metadataMapper.customTableToTableDto(table, hasAccess, table.getDatabase().getIsPublic(),
includeSchema);
final HttpHeaders headers = new HttpHeaders(); final HttpHeaders headers = new HttpHeaders();
if (UserUtil.isSystem(principal)) { if (isSystem(principal)) {
headers.set("X-Username", table.getDatabase().getContainer().getPrivilegedUsername()); headers.set("X-Username", table.getDatabase().getContainer().getPrivilegedUsername());
headers.set("X-Password", table.getDatabase().getContainer().getPrivilegedPassword()); headers.set("X-Password", table.getDatabase().getContainer().getPrivilegedPassword());
headers.set("X-Host", table.getDatabase().getContainer().getHost()); headers.set("X-Host", table.getDatabase().getContainer().getHost());
...@@ -522,9 +504,10 @@ public class TableEndpoint { ...@@ -522,9 +504,10 @@ public class TableEndpoint {
headers.set("X-Table", table.getInternalName()); headers.set("X-Table", table.getInternalName());
headers.set("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database X-Table"); headers.set("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database X-Table");
} }
return ResponseEntity.status(HttpStatus.OK) return ResponseEntity.ok()
.headers(headers) .headers(headers)
.body(dto); .body(metadataMapper.customTableToTableDto(table, hasAccess, table.getDatabase().getIsPublic(),
includeSchema));
} }
@DeleteMapping("/{tableId}") @DeleteMapping("/{tableId}")
...@@ -573,7 +556,7 @@ public class TableEndpoint { ...@@ -573,7 +556,7 @@ public class TableEndpoint {
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final Table table = tableService.findById(database, tableId); final Table table = tableService.findById(database, tableId);
/* roles */ /* roles */
if (!table.getOwner().getUsername().equals(principal.getName()) && !UserUtil.hasRole(principal, "delete-foreign-table")) { if (!table.getOwner().getId().equals(getId(principal)) && !hasRole(principal, "delete-foreign-table")) {
log.error("Failed to delete table: not owned by current user"); log.error("Failed to delete table: not owned by current user");
throw new NotAllowedException("Failed to delete table: not owned by current user"); throw new NotAllowedException("Failed to delete table: not owned by current user");
} }
......
...@@ -14,7 +14,10 @@ import lombok.extern.log4j.Log4j2; ...@@ -14,7 +14,10 @@ import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List; import java.util.List;
...@@ -22,7 +25,7 @@ import java.util.List; ...@@ -22,7 +25,7 @@ import java.util.List;
@CrossOrigin(origins = "*") @CrossOrigin(origins = "*")
@RestController @RestController
@RequestMapping(path = "/api/unit") @RequestMapping(path = "/api/unit")
public class UnitEndpoint { public class UnitEndpoint extends AbstractEndpoint {
private final UnitService unitService; private final UnitService unitService;
private final MetadataMapper metadataMapper; private final MetadataMapper metadataMapper;
...@@ -47,12 +50,11 @@ public class UnitEndpoint { ...@@ -47,12 +50,11 @@ public class UnitEndpoint {
}) })
public ResponseEntity<List<UnitDto>> findAll() { public ResponseEntity<List<UnitDto>> findAll() {
log.debug("endpoint list units"); log.debug("endpoint list units");
final List<UnitDto> dtos = unitService.findAll() return ResponseEntity.ok()
.body(unitService.findAll()
.stream() .stream()
.map(metadataMapper::tableColumnUnitToUnitDto) .map(metadataMapper::tableColumnUnitToUnitDto)
.toList(); .toList());
return ResponseEntity.ok()
.body(dtos);
} }
} }
...@@ -16,7 +16,6 @@ import at.tuwien.mapper.MetadataMapper; ...@@ -16,7 +16,6 @@ import at.tuwien.mapper.MetadataMapper;
import at.tuwien.service.AuthenticationService; import at.tuwien.service.AuthenticationService;
import at.tuwien.service.DatabaseService; import at.tuwien.service.DatabaseService;
import at.tuwien.service.UserService; import at.tuwien.service.UserService;
import at.tuwien.utils.UserUtil;
import io.micrometer.observation.annotation.Observed; import io.micrometer.observation.annotation.Observed;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.ArraySchema;
...@@ -44,7 +43,7 @@ import java.util.UUID; ...@@ -44,7 +43,7 @@ import java.util.UUID;
@CrossOrigin(origins = "*") @CrossOrigin(origins = "*")
@RestController @RestController
@RequestMapping(path = "/api/user") @RequestMapping(path = "/api/user")
public class UserEndpoint { public class UserEndpoint extends AbstractEndpoint {
private final UserService userService; private final UserService userService;
private final MetadataMapper userMapper; private final MetadataMapper userMapper;
...@@ -82,7 +81,8 @@ public class UserEndpoint { ...@@ -82,7 +81,8 @@ public class UserEndpoint {
} }
try { try {
log.trace("filter by username: {}", username); log.trace("filter by username: {}", username);
return ResponseEntity.ok(List.of(userMapper.userToUserBriefDto(userService.findByUsername(username)))); return ResponseEntity.ok(List.of(userMapper.userToUserBriefDto(
userService.findByUsername(username))));
} catch (UserNotFoundException e) { } catch (UserNotFoundException e) {
log.trace("filter by username {} failed: return empty list", username); log.trace("filter by username {} failed: return empty list", username);
return ResponseEntity.ok(List.of()); return ResponseEntity.ok(List.of());
...@@ -141,10 +141,9 @@ public class UserEndpoint { ...@@ -141,10 +141,9 @@ public class UserEndpoint {
log.debug("endpoint create user, data.username={}", data.getUsername()); log.debug("endpoint create user, data.username={}", data.getUsername());
userService.validateUsernameNotExists(data.getUsername()); userService.validateUsernameNotExists(data.getUsername());
userService.validateEmailNotExists(data.getEmail()); userService.validateEmailNotExists(data.getEmail());
final User user = userService.create(data, authenticationService.create(data).getAttributes().getLdapId()[0]);
log.info("Created user with id: {}", user.getId());
return ResponseEntity.status(HttpStatus.CREATED) return ResponseEntity.status(HttpStatus.CREATED)
.body(userMapper.userToUserDto(user)); .body(userMapper.userToUserDto(
userService.create(data, authenticationService.create(data).getAttributes().getLdapId()[0])));
} }
@PostMapping("/token") @PostMapping("/token")
...@@ -193,7 +192,6 @@ public class UserEndpoint { ...@@ -193,7 +192,6 @@ public class UserEndpoint {
AccountNotSetupException { AccountNotSetupException {
log.debug("endpoint get token, data.username={}", data.getUsername()); log.debug("endpoint get token, data.username={}", data.getUsername());
/* check */ /* check */
final TokenDto token = authenticationService.obtainToken(data);
try { try {
userService.findByUsername(data.getUsername()); userService.findByUsername(data.getUsername());
} catch (UserNotFoundException e) { } catch (UserNotFoundException e) {
...@@ -213,7 +211,7 @@ public class UserEndpoint { ...@@ -213,7 +211,7 @@ public class UserEndpoint {
log.info("Patched missing user information for user with username: {}", data.getUsername()); log.info("Patched missing user information for user with username: {}", data.getUsername());
} }
return ResponseEntity.accepted() return ResponseEntity.accepted()
.body(token); .body(authenticationService.obtainToken(data));
} }
@PutMapping("/token") @PutMapping("/token")
...@@ -246,9 +244,8 @@ public class UserEndpoint { ...@@ -246,9 +244,8 @@ public class UserEndpoint {
throws AuthServiceConnectionException, CredentialsInvalidException { throws AuthServiceConnectionException, CredentialsInvalidException {
log.debug("endpoint refresh token"); log.debug("endpoint refresh token");
/* check */ /* check */
final TokenDto token = authenticationService.refreshToken(data.getRefreshToken());
return ResponseEntity.accepted() return ResponseEntity.accepted()
.body(token); .body(authenticationService.refreshToken(data.getRefreshToken()));
} }
@GetMapping("/{userId}") @GetMapping("/{userId}")
...@@ -281,21 +278,18 @@ public class UserEndpoint { ...@@ -281,21 +278,18 @@ public class UserEndpoint {
log.debug("endpoint find a user, userId={}, principal.name={}", userId, principal.getName()); log.debug("endpoint find a user, userId={}, principal.name={}", userId, principal.getName());
/* check */ /* check */
final User user = userService.findById(userId); final User user = userService.findById(userId);
if (!user.getUsername().equals(principal.getName())) { if (!user.getId().equals(getId(principal)) && !hasRole(principal, "find-foreign-user")) {
if (!UserUtil.hasRole(principal, "find-foreign-user")) {
log.error("Failed to find user: foreign user"); log.error("Failed to find user: foreign user");
throw new NotAllowedException("Failed to find user: foreign user"); throw new NotAllowedException("Failed to find user: foreign user");
} }
}
final UserDto dto = userMapper.userToUserDto(user);
final HttpHeaders headers = new HttpHeaders(); final HttpHeaders headers = new HttpHeaders();
if (UserUtil.isSystem(principal)) { if (isSystem(principal)) {
headers.set("X-Username", user.getUsername()); headers.set("X-Username", user.getUsername());
headers.set("X-Password", user.getMariadbPassword()); headers.set("X-Password", user.getMariadbPassword());
} }
return ResponseEntity.status(HttpStatus.OK) return ResponseEntity.status(HttpStatus.OK)
.headers(headers) .headers(headers)
.body(dto); .body(userMapper.userToUserDto(user));
} }
@PutMapping("/{userId}") @PutMapping("/{userId}")
...@@ -333,13 +327,13 @@ public class UserEndpoint { ...@@ -333,13 +327,13 @@ public class UserEndpoint {
UserNotFoundException, DatabaseNotFoundException { UserNotFoundException, DatabaseNotFoundException {
log.debug("endpoint modify a user, userId={}, data={}", userId, data); log.debug("endpoint modify a user, userId={}, data={}", userId, data);
final User user = userService.findById(userId); final User user = userService.findById(userId);
if (!user.getUsername().equals(principal.getName())) { if (!user.getId().equals(getId(principal))) {
log.error("Failed to modify user: not current user {}", user.getId()); log.error("Failed to modify user: not current user {}", user.getId());
throw new NotAllowedException("Failed to modify user: not current user " + user.getId()); throw new NotAllowedException("Failed to modify user: not current user " + user.getId());
} }
final UserDto dto = userMapper.userToUserDto(userService.modify(user, data));
return ResponseEntity.accepted() return ResponseEntity.accepted()
.body(dto); .body(userMapper.userToUserDto(
userService.modify(user, data)));
} }
@PutMapping("/{userId}/password") @PutMapping("/{userId}/password")
...@@ -383,14 +377,14 @@ public class UserEndpoint { ...@@ -383,14 +377,14 @@ public class UserEndpoint {
@NotNull Principal principal) throws NotAllowedException, AuthServiceException, @NotNull Principal principal) throws NotAllowedException, AuthServiceException,
AuthServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, DataServiceException, AuthServiceConnectionException, UserNotFoundException, DatabaseNotFoundException, DataServiceException,
DataServiceConnectionException, CredentialsInvalidException { DataServiceConnectionException, CredentialsInvalidException {
log.debug("endpoint modify a user password, userId={}", userId); log.debug("endpoint modify a user password, userId={}, principal.name={}", userId, principal.getName());
final User user = userService.findById(userId); final User user = userService.findById(userId);
if (!user.getUsername().equals(principal.getName())) { if (!user.getUsername().equals(principal.getName())) {
log.error("Failed to modify user password: not current user"); log.error("Failed to modify user password: not current user");
throw new NotAllowedException("Failed to modify user password: not current user"); throw new NotAllowedException("Failed to modify user password: not current user");
} }
authenticationService.updatePassword(user, data); authenticationService.updatePassword(user, data);
for (Database database : databaseService.findAllAccess(userId)) { for (Database database : databaseService.findAllPublicOrReadAccess(userId)) {
databaseService.updatePassword(database, user); databaseService.updatePassword(database, user);
} }
userService.updatePassword(user, data); userService.updatePassword(user, data);
......
...@@ -13,7 +13,6 @@ import at.tuwien.mapper.MetadataMapper; ...@@ -13,7 +13,6 @@ import at.tuwien.mapper.MetadataMapper;
import at.tuwien.service.DatabaseService; import at.tuwien.service.DatabaseService;
import at.tuwien.service.UserService; import at.tuwien.service.UserService;
import at.tuwien.service.ViewService; import at.tuwien.service.ViewService;
import at.tuwien.utils.UserUtil;
import io.micrometer.observation.annotation.Observed; import io.micrometer.observation.annotation.Observed;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.headers.Header; import io.swagger.v3.oas.annotations.headers.Header;
...@@ -42,7 +41,7 @@ import java.util.stream.Collectors; ...@@ -42,7 +41,7 @@ import java.util.stream.Collectors;
@CrossOrigin(origins = "*") @CrossOrigin(origins = "*")
@RestController @RestController
@RequestMapping(path = "/api/database/{databaseId}/view") @RequestMapping(path = "/api/database/{databaseId}/view")
public class ViewEndpoint { public class ViewEndpoint extends AbstractEndpoint {
private final UserService userService; private final UserService userService;
private final ViewService viewService; private final ViewService viewService;
...@@ -81,13 +80,16 @@ public class ViewEndpoint { ...@@ -81,13 +80,16 @@ public class ViewEndpoint {
DatabaseNotFoundException { DatabaseNotFoundException {
log.debug("endpoint find all views, databaseId={}", databaseId); log.debug("endpoint find all views, databaseId={}", databaseId);
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final User user = principal != null ? userService.findByUsername(principal.getName()) : null; final User caller;
log.trace("find all views for database {}", database); if (principal != null) {
final List<ViewBriefDto> views = viewService.findAll(database, user) caller = userService.findById(getId(principal));
} else {
caller = null;
}
return ResponseEntity.ok(viewService.findAll(database, caller)
.stream() .stream()
.map(metadataMapper::viewToViewBriefDto) .map(metadataMapper::viewToViewBriefDto)
.collect(Collectors.toList()); .collect(Collectors.toList()));
return ResponseEntity.ok(views);
} }
@PostMapping @PostMapping
...@@ -141,17 +143,14 @@ public class ViewEndpoint { ...@@ -141,17 +143,14 @@ public class ViewEndpoint {
UserNotFoundException, SearchServiceException, SearchServiceConnectionException { UserNotFoundException, SearchServiceException, SearchServiceConnectionException {
log.debug("endpoint create view, databaseId={}, data={}", databaseId, data); log.debug("endpoint create view, databaseId={}, data={}", databaseId, data);
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final User caller = userService.findByUsername(principal.getName()); if (!database.getOwner().getId().equals(getId(principal))) {
if (!database.getOwner().getId().equals(caller.getId())) {
log.error("Failed to create view: not the database owner"); log.error("Failed to create view: not the database owner");
throw new NotAllowedException("Failed to create view: not the database owner"); throw new NotAllowedException("Failed to create view: not the database owner");
} }
log.trace("create view for database {}", database); log.trace("create view for database {}", database);
final View view;
view = viewService.create(database, caller, data);
final ViewBriefDto dto = metadataMapper.viewToViewBriefDto(view);
return ResponseEntity.status(HttpStatus.CREATED) return ResponseEntity.status(HttpStatus.CREATED)
.body(dto); .body(metadataMapper.viewToViewBriefDto(
viewService.create(database, userService.findById(getId(principal)), data)));
} }
@GetMapping("/{viewId}") @GetMapping("/{viewId}")
...@@ -193,13 +192,13 @@ public class ViewEndpoint { ...@@ -193,13 +192,13 @@ public class ViewEndpoint {
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final View view = viewService.findById(database, viewId); final View view = viewService.findById(database, viewId);
final HttpHeaders headers = new HttpHeaders(); final HttpHeaders headers = new HttpHeaders();
if (UserUtil.isSystem(principal)) { if (isSystem(principal)) {
headers.set("X-Username", view.getDatabase().getContainer().getPrivilegedUsername()); headers.set("X-Username", database.getContainer().getPrivilegedUsername());
headers.set("X-Password", view.getDatabase().getContainer().getPrivilegedPassword()); headers.set("X-Password", database.getContainer().getPrivilegedPassword());
headers.set("X-Host", view.getDatabase().getContainer().getHost()); headers.set("X-Host", database.getContainer().getHost());
headers.set("X-Port", "" + view.getDatabase().getContainer().getPort()); headers.set("X-Port", "" + database.getContainer().getPort());
headers.set("X-Type", view.getDatabase().getContainer().getImage().getJdbcMethod()); headers.set("X-Type", database.getContainer().getImage().getJdbcMethod());
headers.set("X-Database", view.getDatabase().getInternalName()); headers.set("X-Database", database.getInternalName());
headers.set("X-View", view.getInternalName()); headers.set("X-View", view.getInternalName());
headers.set("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database X-View"); headers.set("Access-Control-Expose-Headers", "X-Username X-Password X-Host X-Port X-Type X-Database X-View");
} }
...@@ -256,7 +255,7 @@ public class ViewEndpoint { ...@@ -256,7 +255,7 @@ public class ViewEndpoint {
SearchServiceConnectionException { SearchServiceConnectionException {
log.debug("endpoint delete view, databaseId={}, viewId={}", databaseId, viewId); log.debug("endpoint delete view, databaseId={}, viewId={}", databaseId, viewId);
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
if (!database.getOwner().getUsername().equals(principal.getName())) { if (!database.getOwner().getId().equals(getId(principal))) {
log.error("Failed to delete view: not the database owner {}", database.getOwner().getId()); log.error("Failed to delete view: not the database owner {}", database.getOwner().getId());
throw new NotAllowedException("Failed to delete view: not the database owner " + database.getOwner().getId()); throw new NotAllowedException("Failed to delete view: not the database owner " + database.getOwner().getId());
} }
...@@ -311,12 +310,13 @@ public class ViewEndpoint { ...@@ -311,12 +310,13 @@ public class ViewEndpoint {
log.debug("endpoint update view, databaseId={}, viewId={}", databaseId, viewId); log.debug("endpoint update view, databaseId={}, viewId={}", databaseId, viewId);
final Database database = databaseService.findById(databaseId); final Database database = databaseService.findById(databaseId);
final View view = viewService.findById(database, viewId); final View view = viewService.findById(database, viewId);
if (!database.getOwner().getUsername().equals(principal.getName()) && !view.getOwner().getUsername().equals(principal.getName())) { if (!database.getOwner().getId().equals(getId(principal)) && !view.getOwner().getId().equals(getId(principal))) {
log.error("Failed to update view: not the database- or view owner"); log.error("Failed to update view: not the database- or view owner");
throw new NotAllowedException("Failed to update view: not the database- or view owner"); throw new NotAllowedException("Failed to update view: not the database- or view owner");
} }
return ResponseEntity.accepted() return ResponseEntity.accepted()
.body(metadataMapper.viewToViewDto(viewService.update(database, view, data))); .body(metadataMapper.viewToViewDto(
viewService.update(database, view, data)));
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment