Skip to content

Commit

Permalink
Merge pull request #279 from kbss-cvut/development
Browse files Browse the repository at this point in the history
[3.1.2] Release
  • Loading branch information
ledsoft authored Jul 23, 2024
2 parents cf5e5f3 + da05402 commit ca4ee3f
Show file tree
Hide file tree
Showing 33 changed files with 1,029 additions and 38 deletions.
9 changes: 9 additions & 0 deletions ontology/termit-glosář.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -631,3 +631,12 @@ termit-pojem:koncový-stav-pojmu
termit:glosář ;
<http://www.w3.org/2004/02/skos/core#prefLabel>
"Terminal term state"@en , "Koncový stav pojmu"@cs .

termit-pojem:požadavek-na-změnu-hesla
a <http://www.w3.org/2004/02/skos/core#Concept> ;
<http://www.w3.org/2004/02/skos/core#broader>
<https://slovník.gov.cz/základní/pojem/typ-objektu> ;
<http://www.w3.org/2004/02/skos/core#inScheme>
termit:glosář ;
<http://www.w3.org/2004/02/skos/core#prefLabel>
"Password reset request"@en , "Požadavek na změnu hesla"@cs .
5 changes: 5 additions & 0 deletions ontology/termit-model.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -333,3 +333,8 @@ termit-pojem:úvodní-stav-pojmu
termit-pojem:koncový-stav-pojmu
a <https://slovník.gov.cz/základní/pojem/typ-objektu>, owl:Class ;
rdfs:subClassOf <http://onto.fel.cvut.cz/ontologies/slovník/agendový/popis-dat/pojem/stav-pojmu> .

termit-pojem:požadavek-na-změnu-hesla
a <https://slovník.gov.cz/základní/pojem/typ-objektu>, owl:Class .


4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</parent>

<artifactId>termit</artifactId>
<version>3.1.1</version>
<version>3.1.2</version>
<name>TermIt</name>
<description>Terminology manager based on Semantic Web technologies.</description>
<packaging>${packaging}</packaging>
Expand Down Expand Up @@ -518,7 +518,7 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.8</version>
<version>0.8.12</version>
<executions>
<execution>
<goals>
Expand Down
46 changes: 46 additions & 0 deletions src/main/java/cz/cvut/kbss/termit/dto/PasswordChangeDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package cz.cvut.kbss.termit.dto;

import cz.cvut.kbss.jopa.model.annotations.Id;
import cz.cvut.kbss.jopa.model.annotations.OWLClass;
import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty;
import cz.cvut.kbss.jopa.vocabulary.DC;
import cz.cvut.kbss.termit.util.Vocabulary;

import java.io.Serializable;
import java.net.URI;

@OWLClass(iri = Vocabulary.ONTOLOGY_IRI_TERMIT + "/password-change")
public class PasswordChangeDto implements Serializable {
@Id
private URI uri;

@OWLDataProperty(iri = DC.Terms.IDENTIFIER)
private String token;

@OWLDataProperty(iri = Vocabulary.s_p_ma_heslo)
private String newPassword;

public URI getUri() {
return uri;
}

public void setUri(URI uri) {
this.uri = uri;
}

public String getToken() {
return token;
}

public void setToken(String token) {
this.token = token;
}

public String getNewPassword() {
return newPassword;
}

public void setNewPassword(String newPassword) {
this.newPassword = newPassword;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package cz.cvut.kbss.termit.dto;

import cz.cvut.kbss.termit.model.UserAccount;
import cz.cvut.kbss.termit.model.util.HasIdentifier;

import java.io.Serializable;
import java.net.URI;
import java.time.Instant;

public class PasswordChangeRequestDto implements Serializable, HasIdentifier {
private URI uri;

/**
* Associated user account.
*/
private UserAccount userAccount;

/**
* Token value.
*/
private String token;

/**
* Token creation timestamp.
*/
private Instant createdAt;

@Override
public URI getUri() {
return uri;
}

@Override
public void setUri(URI uri) {
this.uri = uri;
}

public UserAccount getUserAccount() {
return userAccount;
}

public void setUserAccount(UserAccount userAccount) {
this.userAccount = userAccount;
}

public String getToken() {
return token;
}

public void setToken(String token) {
this.token = token;
}

public Instant getCreatedAt() {
return createdAt;
}

public void setCreatedAt(Instant createdAt) {
this.createdAt = createdAt;
}
}
3 changes: 3 additions & 0 deletions src/main/java/cz/cvut/kbss/termit/dto/mapper/DtoMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package cz.cvut.kbss.termit.dto.mapper;

import cz.cvut.kbss.jopa.model.MultilingualString;
import cz.cvut.kbss.termit.dto.PasswordChangeRequestDto;
import cz.cvut.kbss.termit.dto.RdfsResource;
import cz.cvut.kbss.termit.dto.acl.AccessControlListDto;
import cz.cvut.kbss.termit.dto.acl.AccessControlRecordDto;
Expand Down Expand Up @@ -50,6 +51,8 @@ public abstract class DtoMapper {

public abstract AccessControlListDto accessControlListToDto(AccessControlList acl);

public abstract PasswordChangeRequestDto passwordChangeRequestToDto(PasswordChangeRequest request);

public AccessControlRecordDto accessControlRecordToDto(AccessControlRecord<?> record) {
final AccessControlRecordDto dto = new AccessControlRecordDto();
dto.setUri(record.getUri());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package cz.cvut.kbss.termit.exception;

public class InvalidPasswordChangeRequestException extends AuthorizationException {

private final String messageId;
public InvalidPasswordChangeRequestException(String message, String messageId) {
super(message);
this.messageId = messageId;
}

public String getMessageId() {
return messageId;
}
}
62 changes: 62 additions & 0 deletions src/main/java/cz/cvut/kbss/termit/model/PasswordChangeRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package cz.cvut.kbss.termit.model;

import cz.cvut.kbss.jopa.model.annotations.OWLClass;
import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty;
import cz.cvut.kbss.jopa.model.annotations.OWLObjectProperty;
import cz.cvut.kbss.jopa.model.annotations.ParticipationConstraints;
import cz.cvut.kbss.jopa.vocabulary.DC;
import cz.cvut.kbss.termit.util.Vocabulary;
import jakarta.validation.constraints.NotNull;

import java.time.Instant;

@OWLClass(iri = Vocabulary.s_c_pozadavek_na_zmenu_hesla)
public class PasswordChangeRequest extends AbstractEntity {
/**
* Associated user account.
*/
@NotNull
@ParticipationConstraints(nonEmpty = true)
@OWLObjectProperty(iri = DC.Terms.SUBJECT)
private UserAccount userAccount;

/**
* Token value.
*/
@NotNull
@ParticipationConstraints(nonEmpty = true)
@OWLDataProperty(iri = DC.Terms.IDENTIFIER, simpleLiteral = true)
private String token;

/**
* Token creation timestamp.
*/
@NotNull
@ParticipationConstraints(nonEmpty = true)
@OWLDataProperty(iri = DC.Terms.CREATED)
private Instant createdAt;

public UserAccount getUserAccount() {
return userAccount;
}

public void setUserAccount(UserAccount userAccount) {
this.userAccount = userAccount;
}

public String getToken() {
return token;
}

public void setToken(String token) {
this.token = token;
}

public Instant getCreatedAt() {
return createdAt;
}

public void setCreatedAt(Instant createdAt) {
this.createdAt = createdAt;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package cz.cvut.kbss.termit.persistence.dao;

import cz.cvut.kbss.jopa.model.EntityManager;
import cz.cvut.kbss.termit.exception.PersistenceException;
import cz.cvut.kbss.termit.model.PasswordChangeRequest;
import cz.cvut.kbss.termit.util.Configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Objects;

@Repository
public class PasswordChangeRequestDao extends BaseDao<PasswordChangeRequest> {

private final Configuration.Persistence persistenceConfig;

@Autowired
public PasswordChangeRequestDao(EntityManager em, Configuration configuration) {
super(PasswordChangeRequest.class, em);
this.persistenceConfig = configuration.getPersistence();
}

public List<PasswordChangeRequest> findAllByUsername(String username) {
Objects.requireNonNull(username);
try {
return em.createQuery("SELECT DISTINCT t FROM " + type.getSimpleName() + " t WHERE t.userAccount.username = :username", type)
.setParameter("username", username, persistenceConfig.getLanguage())
.getResultList();
} catch (RuntimeException e) {
throw new PersistenceException(e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package cz.cvut.kbss.termit.rest;

import cz.cvut.kbss.jsonld.JsonLd;
import cz.cvut.kbss.termit.dto.PasswordChangeDto;
import cz.cvut.kbss.termit.service.business.PasswordChangeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@ConditionalOnProperty(prefix = "termit.security", name = "provider", havingValue = "internal", matchIfMissing = true)
@Tag(name = "Password reset", description = "User forgotten password reset API")
@RestController
@RequestMapping("/password")
public class PasswordChangeController {
private static final Logger LOG = LoggerFactory.getLogger(PasswordChangeController.class);

private final PasswordChangeService passwordChangeService;

@Autowired
public PasswordChangeController(PasswordChangeService passwordChangeService) {
this.passwordChangeService = passwordChangeService;
}

@Operation(description = "Requests a password reset for the specified username.")
@ApiResponses({
@ApiResponse(responseCode = "204", description = "Password reset request accepted, email sent"),
@ApiResponse(responseCode = "404", description = "User with the specified username not found.")
})
@PreAuthorize("permitAll()")
@PostMapping(consumes = {MediaType.TEXT_PLAIN_VALUE})
public ResponseEntity<Void> requestPasswordReset(
@Parameter(description = "Username of the user") @RequestBody String username) {
LOG.info("Password reset requested for user {}.", username);
passwordChangeService.requestPasswordReset(username);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}

@Operation(description = "Changes the password for the specified user.")
@ApiResponses({
@ApiResponse(responseCode = "204", description = "Password changed"),
@ApiResponse(responseCode = "409", description = "Invalid or expired token")
})
@PreAuthorize("permitAll()")
@PutMapping(consumes = {MediaType.APPLICATION_JSON_VALUE, JsonLd.MEDIA_TYPE})
public ResponseEntity<Void> changePassword(
@Parameter(
description = "Token with URI for password reset") @RequestBody PasswordChangeDto passwordChangeDto) {
LOG.info("Password change requested with token {}", passwordChangeDto.getToken());
passwordChangeService.changePassword(passwordChangeDto);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,10 @@ public void removeVocabulary(@Parameter(description = ApiDoc.ID_LOCAL_NAME_DESCR
@RequestParam(name = QueryParams.NAMESPACE,
required = false) Optional<String> namespace) {
final URI identifier = resolveIdentifier(namespace.orElse(config.getNamespace().getVocabulary()), localName);
final Vocabulary toRemove = vocabularyService.getReference(identifier);
vocabularyService.remove(toRemove);
LOG.debug("Vocabulary {} removed.", toRemove);
vocabularyService.find(identifier).ifPresent(toRemove -> {
vocabularyService.remove(toRemove);
LOG.debug("Vocabulary {} removed.", toRemove);
});
}

@Operation(description = "Validates the terms in a vocabulary with the specified identifier.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import cz.cvut.kbss.termit.exception.AuthorizationException;
import cz.cvut.kbss.termit.exception.InvalidLanguageConstantException;
import cz.cvut.kbss.termit.exception.InvalidParameterException;
import cz.cvut.kbss.termit.exception.InvalidPasswordChangeRequestException;
import cz.cvut.kbss.termit.exception.InvalidTermStateException;
import cz.cvut.kbss.termit.exception.NotFoundException;
import cz.cvut.kbss.termit.exception.PersistenceException;
Expand Down Expand Up @@ -234,4 +235,10 @@ public ResponseEntity<ErrorInfo> vocabularyImportException(HttpServletRequest re
ErrorInfo.createWithMessageAndMessageId(e.getMessage(), e.getMessageId(), request.getRequestURI()),
HttpStatus.CONFLICT);
}

@ExceptionHandler
public ResponseEntity<ErrorInfo> invalidPasswordChangeRequestException(HttpServletRequest request, InvalidPasswordChangeRequestException e) {
logException(e, request);
return new ResponseEntity<>(ErrorInfo.createWithMessageAndMessageId(e.getMessage(), e.getMessageId(), request.getRequestURI()), HttpStatus.CONFLICT);
}
}
Loading

0 comments on commit ca4ee3f

Please sign in to comment.