Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update NodeBB api to internal v3 api #904

Merged
merged 2 commits into from
Nov 6, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 44 additions & 18 deletions src/main/java/com/faforever/api/forum/NodebbService.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand All @@ -30,7 +31,7 @@ public class NodebbService implements UserDataSyncService, InitializingBean {
private final FafApiProperties properties;

@Override
public void afterPropertiesSet() throws Exception {
public void afterPropertiesSet() {
log.info("NodeBB service initialized");
}

Expand All @@ -39,7 +40,11 @@ public void userDataChanged(UserUpdatedEvent event) {
try {
getNodebbUserId(event.getId())
.ifPresentOrElse(
userId -> updateUserData(userId, event),
userId -> {
updateUsernameData(userId, event);
updateEmailData(userId, event);
log.info("User data updated in NodeBB: username={}, email={}", event.getUsername(), event.getEmail());
},
() -> log.info("User data not updated in NodeBB (User not found): {}", event)
);
} catch (Exception e) {
Expand All @@ -50,13 +55,14 @@ public void userDataChanged(UserUpdatedEvent event) {
private Optional<Integer> getNodebbUserId(int userId) {
URI uri = UriComponentsBuilder.fromHttpUrl(properties.getNodebb().getBaseUrl())
// This is not an official NodeBB api url, it's coming from our own sso plugin
.pathSegment("api", "user", "oauth", String.valueOf(userId))
.pathSegment("api", "v3", "plugins", "sso", "user", String.valueOf(userId))
.queryParam("_uid", getAdminUserId())
.build()
.toUri();

try {
ResponseEntity<UserResponse> result = restTemplate.exchange(uri, HttpMethod.GET, null, UserResponse.class);
return Optional.of(result.getBody().uid);
ResponseEntity<UserResponse> result = restTemplate.exchange(uri, HttpMethod.GET, buildAuthorizedRequest(null), UserResponse.class);
return Optional.ofNullable(result.getBody()).map(UserResponse::uid);
} catch (HttpClientErrorException e) {
if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
log.debug("User id {} not found in NodeBB. Probably the user never logged in there and has no account there.", userId);
Expand All @@ -67,21 +73,35 @@ private Optional<Integer> getNodebbUserId(int userId) {
}
}

private void updateUserData(int nodebbUserId, UserUpdatedEvent event) {
private void updateUsernameData(int nodebbUserId, UserUpdatedEvent event) {
URI uri = UriComponentsBuilder.fromHttpUrl(properties.getNodebb().getBaseUrl())
.pathSegment("api", "v2", "users", String.valueOf(nodebbUserId))
.pathSegment("api", "v3", "users", String.valueOf(nodebbUserId))
.build()
.toUri();

UserUpdate userUpdate = new UserUpdate(String.valueOf(properties.getNodebb().getAdminUserId()),
event.getUsername(), event.getEmail());
restTemplate.exchange(uri, HttpMethod.PUT, buildAuthorizedRequest(userUpdate), Void.class);
log.info("User data updated in NodeBB: {}", event);
var usernameUpdate = new UsernameUpdate(getAdminUserId(), event.getUsername());
restTemplate.exchange(uri, HttpMethod.PUT, buildAuthorizedRequest(usernameUpdate), Void.class);
log.debug("Username updated in NodeBB: {}", event);
}

private void updateEmailData(int nodebbUserId, UserUpdatedEvent event) {
URI uri = UriComponentsBuilder.fromHttpUrl(properties.getNodebb().getBaseUrl())
.pathSegment("api", "v3", "users", String.valueOf(nodebbUserId), "emails")
.build()
.toUri();

var usernameUpdate = new EmailUpdate(getAdminUserId(), event.getEmail(), 1);
restTemplate.exchange(uri, HttpMethod.POST, buildAuthorizedRequest(usernameUpdate), Void.class);
log.debug("Email updated in NodeBB: {}", event);
}

private String getAdminUserId() {
return String.valueOf(properties.getNodebb().getAdminUserId());
}

private <T> HttpEntity<T> buildAuthorizedRequest(T payload) {
LinkedMultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add("Authorization", "Bearer " + properties.getNodebb().getMasterToken());
headers.add(HttpHeaders.AUTHORIZATION, "Bearer " + properties.getNodebb().getMasterToken());

return new HttpEntity<>(payload, headers);
}
Expand All @@ -90,13 +110,19 @@ private <T> HttpEntity<T> buildAuthorizedRequest(T payload) {
public record UserResponse(Integer uid, String username) {
}

private record UserUpdate(
/**
ID of the user to impersonate for the http call (should be an admin user if username change is disabled)
*/
private record UsernameUpdate(
// ID of the user to impersonate for the http call (should be an admin user if username change is disabled)
String _uid,
String username
) {
}

private record EmailUpdate(
// ID of the user to impersonate for the http call (should be an admin user if username change is disabled)
String _uid,
String username,
String email
String email,
// must always be 1
int skipConfirmation
) {
}
}
Loading