Skip to content

Commit

Permalink
Create code service and code controller
Browse files Browse the repository at this point in the history
  • Loading branch information
Fagorym committed Dec 10, 2023
1 parent 707a4b6 commit 7b145c7
Show file tree
Hide file tree
Showing 14 changed files with 318 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@
import ru.nsu.fit.directors.userservice.dto.response.BaseResponse;
import ru.nsu.fit.directors.userservice.exception.BaseException;
import ru.nsu.fit.directors.userservice.exception.ClientException;
import ru.nsu.fit.directors.userservice.exception.IncorrectPhoneNumberFormatException;
import ru.nsu.fit.directors.userservice.exception.OrderBookingTimeException;
import ru.nsu.fit.directors.userservice.exception.ServerNotAvailableException;
import ru.nsu.fit.directors.userservice.exception.UserAlreadyExistsException;
import ru.nsu.fit.directors.userservice.exception.UserNotFoundException;
import ru.nsu.fit.directors.userservice.exception.VerificationCodeWasFalseException;
import ru.nsu.fit.directors.userservice.exception.WrongCredentialsException;

import java.util.LinkedHashMap;
Expand All @@ -43,7 +45,9 @@ public class ArticleController extends ResponseEntityExceptionHandler implements
WrongCredentialsException.class,
OrderBookingTimeException.class,
ServerNotAvailableException.class,
ClientException.class
ClientException.class,
VerificationCodeWasFalseException.class,
IncorrectPhoneNumberFormatException.class
})
public <T extends BaseException> ResponseEntity<BaseResponse<Object>> handleException(T e) {
BaseResponse<Object> response = new BaseResponse<>(e.getMessage(), e.getType());
Expand Down Expand Up @@ -107,7 +111,6 @@ protected ResponseEntity<Object> handleHttpMessageNotReadable(
return new ResponseEntity<>(response, HttpStatus.OK);
}


@NonNull
private String getDefaultMessage(BindException ex) {
return ex.getBindingResult()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package ru.nsu.fit.directors.userservice.controller;

import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import ru.nsu.fit.directors.userservice.dto.request.RequestCodeDto;
import ru.nsu.fit.directors.userservice.service.CodeService;

/**
* Class that represents code controller.
* Main aim of this controller - creating user codes and checking user codes.
*/
@RestController
@RequestMapping(value = "/user/code", produces = MediaType.APPLICATION_JSON_VALUE)
@RequiredArgsConstructor(access = AccessLevel.PUBLIC)
@CrossOrigin(allowCredentials = "true", originPatterns = {"*"})
public class CodeController {
private final CodeService codeService;

/**
* Get request, that creates code for user registration.
*
* @param phoneNumber of user, who wants to register his account.
* @return boolean variable, that indicates success of this request.
*/
// TODO: GET -> POST
@GetMapping
public Boolean getCode(@RequestParam String phoneNumber) {
return codeService.generateCode(phoneNumber);
}

// TODO: VALID Code Dto

/**
* Post request, that validate existing of registration code in our database.
*
* @param codeDto contains phoneNumber and code, that we need to check
* @return true - if code was in database, false - if there is no such code
*/
@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
public Boolean checkCode(@RequestBody RequestCodeDto codeDto) {
return codeService.checkCode(codeDto.phoneNumber(), codeDto.code());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ru.nsu.fit.directors.userservice.dto.request;

public record RequestCodeDto(
String code,
String phoneNumber
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package ru.nsu.fit.directors.userservice.enums;

public enum CodeType {
registration,
booking
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ru.nsu.fit.directors.userservice.exception;

/**
* Child of base exception.
* Throw this exception, when user try to provide wrong phone number format.
*/
public class IncorrectPhoneNumberFormatException extends BaseException {
static final private String ERROR_TYPE = "IncorrectPhoneNumberFormatException";

public IncorrectPhoneNumberFormatException() {
super("Номер телефона введен в неверном формате.", ERROR_TYPE);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package ru.nsu.fit.directors.userservice.exception;

public class VerificationCodeWasFalseException extends BaseException {
private final static String ERROR_TYPE = "VerificationCodeWasFalseException";
private final static String ERROR_MESSAGE =
"Код, который был введен, оказался неправильным. Попробуйте ввести его еще раз.";

public VerificationCodeWasFalseException() {
super(ERROR_MESSAGE, ERROR_TYPE);
}
}
39 changes: 39 additions & 0 deletions src/main/java/ru/nsu/fit/directors/userservice/model/Code.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package ru.nsu.fit.directors.userservice.model;

import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import ru.nsu.fit.directors.userservice.enums.CodeType;

import java.time.LocalDateTime;

@Entity
@Table(name = "code")
@Getter
@Setter
@Builder
@AllArgsConstructor
public class Code {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String phoneNumber;
private String code;
@CreationTimestamp
private LocalDateTime createdAt;
@Enumerated(EnumType.STRING)
private CodeType type;

public Code() {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package ru.nsu.fit.directors.userservice.repository;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import ru.nsu.fit.directors.userservice.model.Code;

@Repository
public interface CodeRepository extends JpaRepository<Code, Long> {
Optional<Code> findByPhoneNumberAndCode(String phoneNumber, String codeString);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package ru.nsu.fit.directors.userservice.service;

/**
* Service, that responsible for verification codes.
*/
public interface CodeService {
/**
* Method, that checking existing of the code in our database.
*
* @param phoneNumber - with what phone number must be associated code.
* @param code - code, that user provided as his code.
* @return true - if data is valid, false - otherwise.
*/
boolean checkCode(String phoneNumber, String code);

/**
* Method, that generated code by user request and put it into database.
* Also, verified phone number in API service.
*
* @param phoneNumber - for what number we need to generate code.
* @return true - if was success, false - otherwise.
*/

boolean generateCode(String phoneNumber);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package ru.nsu.fit.directors.userservice.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import ru.nsu.fit.directors.userservice.enums.CodeType;
import ru.nsu.fit.directors.userservice.exception.IncorrectPhoneNumberFormatException;
import ru.nsu.fit.directors.userservice.exception.UserAlreadyExistsException;
import ru.nsu.fit.directors.userservice.exception.VerificationCodeWasFalseException;
import ru.nsu.fit.directors.userservice.model.Code;
import ru.nsu.fit.directors.userservice.repository.CodeRepository;
import ru.nsu.fit.directors.userservice.repository.UserRepository;

import java.util.Map;
import java.util.Optional;

@Service
@RequiredArgsConstructor
@Slf4j
public class CodeServiceImpl implements CodeService {
private final CodeRepository codeRepository;
private final UserRepository userRepository;
private final RequestSenderService requestSenderService;

@Override
public boolean checkCode(String phoneNumber, String codeString) {
log.info("Checking code");
Optional<Code> code = codeRepository.findByPhoneNumberAndCode(phoneNumber, codeString);
if (code.isPresent()) {
codeRepository.delete(code.get());
log.info("Checking code was true");
return true;
} else {
throw new VerificationCodeWasFalseException();
}
}

@Override
public boolean generateCode(String phoneNumber) {
log.info("Generating code");
if (userRepository.existsByPhoneNumber(phoneNumber)) {
log.warn("User with number " + phoneNumber + " already exists");
throw new UserAlreadyExistsException();
} else {
Map<String, Object> response = requestSenderService.sendRequest(phoneNumber);
if (codeRequestWasFalse(response)) {
log.warn("Checking code for " + phoneNumber + " was false");
throw new IncorrectPhoneNumberFormatException();
} else {
log.info("Creating new instance of code");
Code code = new Code();
code.setCode((String) response.get("code"));
code.setPhoneNumber(phoneNumber);
code.setType(CodeType.registration);
codeRepository.save(code);
log.info("Code " + code + "was created successfully ");
return true;
}
}
}

private boolean codeRequestWasFalse(Map<String, Object> response) {
return response.get("status").equals(false);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ru.nsu.fit.directors.userservice.service;

import java.util.Map;

public interface RequestSenderService {
Map<String, Object> sendRequest(String phoneNumber);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package ru.nsu.fit.directors.userservice.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

import javax.annotation.ParametersAreNonnullByDefault;

@Service
@RequiredArgsConstructor
@ParametersAreNonnullByDefault
@Slf4j
public class RequestSenderServiceImpl implements RequestSenderService {

public Map<String, Object> sendRequest(String phoneNumber) {

if (!phoneNumber.startsWith("7")) {
phoneNumber = phoneNumber.substring(1);
}

String requestString = "https://api.ucaller.ru/v1.0/initCall?" +
"phone=" + phoneNumber +
"&voice=" + "false" +
"&key=1vvjxSFMby9xJx783gk31AT7UDPEHBdI" +
"&service_id=317622";

Map<String, Object> map = null;

try {
log.info("Request to UCaller API was sent");
URL request = new URL(requestString);
HttpURLConnection connection = (HttpURLConnection) request.openConnection();
connection.setRequestMethod("GET");
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));

String inputLine;
StringBuilder response = new StringBuilder();

while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
log.info("Response was received");
ObjectMapper objectMapper = new ObjectMapper();
map = objectMapper.readValue(
response.toString(), new TypeReference<>() {
});
log.debug("Response was: " + response);
connection.disconnect();

} catch (IOException exception) {
log.warn(exception.getMessage());
}
return map;
}
}
6 changes: 3 additions & 3 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
spring.datasource.url=${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:8000/user_service}
spring.datasource.username=postgres
spring.datasource.password=xzq75757
spring.datasource.password=postgres
spring.datasource.driver-class-name=org.postgresql.Driver

spring.flyway.password=${SPRING_DATASOURCE_PASSWORD:xzq75757}
spring.flyway.password=${SPRING_DATASOURCE_PASSWORD:postgres}
spring.flyway.user=${SPRING_DATASOURCE_USERNAME:postgres}
spring.flyway.url=${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:8000/user_service}
spring.flyway.locations=classpath:db/migration
Expand Down Expand Up @@ -43,4 +43,4 @@ server.servlet.session.cookie.secure=true
server.servlet.session.cookie.name=JSESSIONID_${spring.application.name}


vk.api.service-key=${VK_SERVICE_KEY: 0}
vk.api.service-key=${VK_SERVICE_KEY: 0}
8 changes: 8 additions & 0 deletions src/main/resources/db/migration/V6__create_code.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
create table code
(
id bigserial primary key,
code varchar,
phone_number varchar,
created_at timestamp default now(),
type varchar not null
)

0 comments on commit 7b145c7

Please sign in to comment.