Skip to content

Commit

Permalink
Feature: Discord auth.
Browse files Browse the repository at this point in the history
  • Loading branch information
Mateusz Czeladka committed Sep 15, 2023
1 parent f8301f6 commit c45814b
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.ToString;

@AllArgsConstructor
@Getter
@ToString
public class IsVerifiedResponse {

private boolean isVerified;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
public class DiscordUserVerification extends AbstractTimestampEntity {

@Id
@Column(name = "discord_id_hash", nullable = false)
@Column(name = "id", nullable = false)
@Getter
@Setter
private String discordIdHash;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,19 @@
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.cardano.foundation.voting.domain.IsVerifiedRequest;
import org.cardano.foundation.voting.domain.discord.DiscordCheckVerificationRequest;
import org.cardano.foundation.voting.domain.discord.DiscordStartVerificationRequest;
import org.cardano.foundation.voting.service.discord.DiscordUserVerificationService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Objects;

import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;

Expand All @@ -21,34 +26,54 @@
@RequiredArgsConstructor
public class DiscordUserVerificationResource {

private final DiscordUserVerificationService discordUserVerificationService;

@Value("${discord.bot.eventId.binding}")
private String discordBotEventIdBinding;

@RequestMapping(value = "/is-verified/{discordIdHash}", method = GET, produces = "application/json")
@Timed(value = "resource.discord.isVerified", histogram = true)
public ResponseEntity<?> isDiscordUserVerified(@PathVariable("hashedDiscordId") String hashedDiscordId) {
log.info("Received isDiscordUserVerified hashedDiscordId: {}", hashedDiscordId);
public ResponseEntity<?> isDiscordUserVerified(@PathVariable("discordIdHash") String discordIdHash) {
log.info("Received isDiscordUserVerified request discordIdHash: {}", discordIdHash);

// TODO

return ResponseEntity.ok().build();
return discordUserVerificationService.isVerified(new IsVerifiedRequest(discordBotEventIdBinding, discordIdHash))
.fold(problem -> {
return ResponseEntity.status(Objects.requireNonNull(problem.getStatus()).getStatusCode()).body(problem);
},
userVerification -> {
return ResponseEntity.ok().body(userVerification);
}
);
}

@RequestMapping(value = "/start-verification", method = POST, produces = "application/json")
@Timed(value = "resource.discord.startVerification", histogram = true)
public ResponseEntity<?> startVerification(@RequestBody @Valid DiscordStartVerificationRequest startVerificationRequest) {
log.info("Received discord startVerification request: {}", startVerificationRequest);

// TODO

return ResponseEntity.ok().build();
return discordUserVerificationService.startVerification(startVerificationRequest)
.fold(problem -> {
return ResponseEntity.status(Objects.requireNonNull(problem.getStatus()).getStatusCode()).body(problem);
},
userVerification -> {
return ResponseEntity.ok().body(userVerification);
}
);
}

@RequestMapping(value = "/check-verification", method = POST, produces = "application/json")
@Timed(value = "resource.discord.checkVerification", histogram = true)
public ResponseEntity<?> checkVerification(@RequestBody @Valid DiscordCheckVerificationRequest checkVerificationRequest) {
log.info("Received discord checkVerification request: {}", checkVerificationRequest);

// TODO

return ResponseEntity.ok().build();
return discordUserVerificationService.checkVerification(checkVerificationRequest)
.fold(problem -> {
return ResponseEntity.status(Objects.requireNonNull(problem.getStatus()).getStatusCode()).body(problem);
},
userVerification -> {
return ResponseEntity.ok().body(userVerification);
}
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
import org.cardano.foundation.voting.domain.IsVerifiedResponse;
import org.cardano.foundation.voting.service.discord.DiscordUserVerificationService;
import org.cardano.foundation.voting.service.sms.SMSUserVerificationService;
import org.cardano.foundation.voting.utils.CompletableFutures;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.zalando.problem.Problem;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

Expand All @@ -34,7 +36,7 @@ public class UserVerificationResource {
@Timed(value = "resource.isVerified", histogram = true)
public ResponseEntity<?> isVerified(@PathVariable("eventId") String eventId,
@PathVariable("stakeAddress") String stakeAddress) throws ExecutionException, InterruptedException {
var isVerifiedRequest = new IsVerifiedRequest(stakeAddress, eventId);
var isVerifiedRequest = new IsVerifiedRequest(eventId, stakeAddress);

log.info("Received isVerified request: {}", isVerifiedRequest);

Expand All @@ -46,19 +48,26 @@ public ResponseEntity<?> isVerified(@PathVariable("eventId") String eventId,
return discordUserVerificationService.isVerified(isVerifiedRequest);
});

var isVerified = CompletableFuture.anyOf(smsVerificationFuture, discordVerificationFuture);
var allFutures = CompletableFutures.anyResultsOf(List.of(smsVerificationFuture, discordVerificationFuture));

var isVerifiedResponseE = (Either<Problem, IsVerifiedResponse>) isVerified
.orTimeout(30, SECONDS)
.get();
List<Either<Problem, IsVerifiedResponse>> allResponses = allFutures.orTimeout(30, SECONDS)
.join();

return isVerifiedResponseE.fold(problem -> {
return ResponseEntity.status(problem.getStatus().getStatusCode()).body(problem);
},
isVerifiedResponse -> {
return ResponseEntity.ok().body(isVerifiedResponse);
}
);
var successCount = allResponses.stream().filter(Either::isRight).count();

if (successCount != 2) {
var problem = allResponses.stream().filter(Either::isLeft).findFirst().orElseThrow().getLeft();

return ResponseEntity.status(problem.getStatus().getStatusCode()).body(problem);
}

var successes = allResponses.stream().filter(Either::isRight).toList().stream().map(Either::get).toList();

var isVerified = successes.stream().reduce((a, b) -> {
return new IsVerifiedResponse(a.isVerified() || b.isVerified());
}).orElse(new IsVerifiedResponse(false));

return ResponseEntity.ok().body(isVerified);
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.cardano.foundation.voting.service.discord;

import io.vavr.control.Either;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.cardano.foundation.voting.client.ChainFollowerClient;
import org.cardano.foundation.voting.domain.CardanoNetwork;
Expand Down Expand Up @@ -33,7 +32,6 @@

@Service
@Slf4j
@AllArgsConstructor
public class DefaultDiscordUserVerificationService implements DiscordUserVerificationService {

@Autowired
Expand Down Expand Up @@ -90,7 +88,7 @@ public Either<Problem, DiscordStartVerificationResponse> startVerification(Disco

var maybeEvent = eventDetails.get();
if (maybeEvent.isEmpty()) {
log.warn("Active event not found:{}", discordBotEventIdBinding);
log.warn("Event not found:{}", discordBotEventIdBinding);

return Either.left(Problem.builder()
.withTitle("EVENT_NOT_FOUND")
Expand Down Expand Up @@ -134,7 +132,7 @@ public Either<Problem, IsVerifiedResponse> checkVerification(DiscordCheckVerific

var maybeEvent = eventDetails.get();
if (maybeEvent.isEmpty()) {
log.warn("Active event not found:{}", discordBotEventIdBinding);
log.warn("Event not found:{}", discordBotEventIdBinding);

return Either.left(Problem.builder()
.withTitle("EVENT_NOT_FOUND")
Expand Down Expand Up @@ -243,7 +241,7 @@ public Either<Problem, IsVerifiedResponse> checkVerification(DiscordCheckVerific
);
}

DiscordUserVerification pendingUserVerification = maybePendingVerification.orElseThrow();
var pendingUserVerification = maybePendingVerification.orElseThrow();

var now = LocalDateTime.now(clock);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public Either<Problem, SMSStartVerificationResponse> startVerification(SMSStartV

var maybeEvent = eventDetails.get();
if (maybeEvent.isEmpty()) {
log.warn("Active event not found:{}", eventId);
log.warn("Event not found:{}", eventId);

return Either.left(Problem.builder()
.withTitle("EVENT_NOT_FOUND")
Expand Down Expand Up @@ -238,7 +238,7 @@ public Either<Problem, IsVerifiedResponse> checkVerification(SMSCheckVerificatio

var maybeEvent = activeEventE.get();
if (maybeEvent.isEmpty()) {
log.error("Active event not found:{}", eventId);
log.error("Event not found:{}", eventId);

return Either.left(Problem.builder()
.withTitle("EVENT_NOT_FOUND")
Expand Down Expand Up @@ -345,7 +345,7 @@ public Either<Problem, IsVerifiedResponse> isVerified(IsVerifiedRequest isVerifi

var maybeEvent = activeEventE.get();
if (maybeEvent.isEmpty()) {
log.error("Active event not found:{}", isVerifiedRequest.getEventId());
log.error("Event not found:{}", isVerifiedRequest.getEventId());

return Either.left(Problem.builder()
.withTitle("EVENT_NOT_FOUND")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.cardano.foundation.voting.utils;

import java.util.List;
import java.util.concurrent.CompletableFuture;

public final class CompletableFutures {

public static <T> CompletableFuture<List<T>> anyResultsOf(List<CompletableFuture<T>> completableFutures) {
var allFutures = CompletableFuture
.anyOf(completableFutures.toArray(new CompletableFuture[completableFutures.size()]));

return allFutures.thenApply(
future -> {
return completableFutures.stream()
.map(CompletableFuture::join)
.toList();
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ create index idx_sms_stake_address_status_phone_hash on sms_user_verification(ev
create index idx_sms_stake_address_status_req_id on sms_user_verification(event_id, stake_address, status, request_id);

CREATE TABLE discord_user_verification (
discord_id_hash VARCHAR(255) NOT NULL,
id VARCHAR(255) NOT NULL, -- discord id hash

event_id VARCHAR(255) NOT NULL,

Expand All @@ -47,7 +47,7 @@ CREATE TABLE discord_user_verification (
created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,

CONSTRAINT pk_discord_id_hash PRIMARY KEY (discord_id_hash)
CONSTRAINT pk_discord_id_hash PRIMARY KEY (id)
);

create index idx_discord_stake_event_id on sms_user_verification(event_id);
Expand All @@ -56,4 +56,4 @@ create index idx_discord_event_id_status on sms_user_verification(event_id, stat

create index idx_discord_stake_address_status on sms_user_verification(event_id, stake_address, status);

create index idx_discord_status_event_discord_id_hash on sms_user_verification(event_id, status, discord_id_hash);
create index idx_discord_status_event_discord_id_hash on sms_user_verification(event_id, status, id);
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ create index idx_sms_stake_address_status_phone_hash on sms_user_verification(ev
create index idx_sms_stake_address_status_req_id on sms_user_verification(event_id, stake_address, status, request_id);

CREATE TABLE discord_user_verification (
discord_id_hash VARCHAR(255) NOT NULL,
id VARCHAR(255) NOT NULL, -- discord id hash

event_id VARCHAR(255) NOT NULL,

Expand All @@ -47,7 +47,7 @@ CREATE TABLE discord_user_verification (
created_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,
updated_at TIMESTAMP WITHOUT TIME ZONE NOT NULL,

CONSTRAINT pk_discord_id_hash PRIMARY KEY (discord_id_hash)
CONSTRAINT pk_discord_id_hash PRIMARY KEY (id)
);

create index idx_discord_stake_event_id on sms_user_verification(event_id);
Expand All @@ -56,4 +56,4 @@ create index idx_discord_event_id_status on sms_user_verification(event_id, stat

create index idx_discord_stake_address_status on sms_user_verification(event_id, stake_address, status);

create index idx_discord_status_event_discord_id_hash on sms_user_verification(event_id, status, discord_id_hash);
create index idx_discord_status_event_discord_id_hash on sms_user_verification(event_id, status, id);
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ private Either<Problem, Boolean> isHighLevelEventLeaderboardAvailable(ChainFollo
return Either.right(eventDetails.proposalsReveal());
}


private Either<Problem, Boolean> isHighLevelCategoryLeaderboardAvailable(ChainFollowerClient.EventDetailsResponse eventDetails,
boolean forceLeaderboard) {
if (forceLeaderboard) {
Expand Down Expand Up @@ -70,7 +69,8 @@ private Either<Problem, Boolean> isCategoryLeaderboardAvailable(ChainFollowerCli
}

@Override
public Either<Problem, Boolean> isHighLevelEventLeaderboardAvailable(String event, boolean forceLeaderboard) {
public Either<Problem, Boolean> isHighLevelEventLeaderboardAvailable(String event,
boolean forceLeaderboard) {
var eventDetailsE = chainFollowerClient.getEventDetails(event);
if (eventDetailsE.isEmpty()) {
return Either.left(Problem.builder()
Expand Down Expand Up @@ -159,7 +159,6 @@ public Either<Problem, Leaderboard.ByEventStats> getEventLeaderboard(String even

var votes = voteRepository.getHighLevelEventStats(event);
if (votes.isEmpty()) {

Leaderboard.ByEventStats.ByEventStatsBuilder byEventStatsBuilder = Leaderboard.ByEventStats.builder()
.event(eventDetails.id())
.totalVotesCount(0L);
Expand Down

0 comments on commit c45814b

Please sign in to comment.