Compare commits

...

2 Commits

Author SHA1 Message Date
Tim
8544803e62 feat: shorten invite links 2025-09-01 11:25:32 +08:00
Tim
90eee03198 Merge pull request #807 from nagisa77/codex/fix-backend-compilation-issues
test: fix PostServiceTest for new PostService deps
2025-09-01 10:54:07 +08:00
3 changed files with 37 additions and 6 deletions

View File

@@ -14,6 +14,13 @@ public class InviteToken {
@Id @Id
private String token; private String token;
/**
* Short token used in invite links. Existing records may have this field null
* and fall back to {@link #token} for backward compatibility.
*/
@Column(unique = true)
private String shortToken;
@ManyToOne @ManyToOne
private User inviter; private User inviter;

View File

@@ -9,4 +9,8 @@ import java.util.Optional;
public interface InviteTokenRepository extends JpaRepository<InviteToken, String> { public interface InviteTokenRepository extends JpaRepository<InviteToken, String> {
Optional<InviteToken> findByInviterAndCreatedDate(User inviter, LocalDate createdDate); Optional<InviteToken> findByInviterAndCreatedDate(User inviter, LocalDate createdDate);
Optional<InviteToken> findByShortToken(String shortToken);
boolean existsByShortToken(String shortToken);
} }

View File

@@ -30,33 +30,53 @@ public class InviteService {
LocalDate today = LocalDate.now(); LocalDate today = LocalDate.now();
Optional<InviteToken> existing = inviteTokenRepository.findByInviterAndCreatedDate(inviter, today); Optional<InviteToken> existing = inviteTokenRepository.findByInviterAndCreatedDate(inviter, today);
if (existing.isPresent()) { if (existing.isPresent()) {
return existing.get().getToken(); InviteToken inviteToken = existing.get();
return inviteToken.getShortToken() != null ? inviteToken.getShortToken() : inviteToken.getToken();
} }
String token = jwtService.generateInviteToken(username); String token = jwtService.generateInviteToken(username);
String shortToken;
do {
shortToken = java.util.UUID.randomUUID().toString().replace("-", "").substring(0, 8);
} while (inviteTokenRepository.existsByShortToken(shortToken));
InviteToken inviteToken = new InviteToken(); InviteToken inviteToken = new InviteToken();
inviteToken.setToken(token); inviteToken.setToken(token);
inviteToken.setShortToken(shortToken);
inviteToken.setInviter(inviter); inviteToken.setInviter(inviter);
inviteToken.setCreatedDate(today); inviteToken.setCreatedDate(today);
inviteToken.setUsageCount(0); inviteToken.setUsageCount(0);
inviteTokenRepository.save(inviteToken); inviteTokenRepository.save(inviteToken);
return token; return shortToken;
} }
public InviteValidateResult validate(String token) { public InviteValidateResult validate(String token) {
if (token == null || token.isEmpty()) { if (token == null || token.isEmpty()) {
return new InviteValidateResult(null, false); return new InviteValidateResult(null, false);
} }
InviteToken invite = inviteTokenRepository.findById(token).orElse(null);
String realToken = token;
if (invite == null) {
invite = inviteTokenRepository.findByShortToken(token).orElse(null);
if (invite == null) {
return new InviteValidateResult(null, false);
}
realToken = invite.getToken();
}
try { try {
jwtService.validateAndGetSubjectForInvite(token); jwtService.validateAndGetSubjectForInvite(realToken);
} catch (Exception e) { } catch (Exception e) {
return new InviteValidateResult(null, false); return new InviteValidateResult(null, false);
} }
InviteToken invite = inviteTokenRepository.findById(token).orElse(null);
return new InviteValidateResult(invite, invite != null && invite.getUsageCount() < 3); return new InviteValidateResult(invite, invite.getUsageCount() < 3);
} }
public void consume(String token, String newUserName) { public void consume(String token, String newUserName) {
InviteToken invite = inviteTokenRepository.findById(token).orElseThrow(); InviteToken invite = inviteTokenRepository.findById(token)
.orElseGet(() -> inviteTokenRepository.findByShortToken(token).orElseThrow());
invite.setUsageCount(invite.getUsageCount() + 1); invite.setUsageCount(invite.getUsageCount() + 1);
inviteTokenRepository.save(invite); inviteTokenRepository.save(invite);
pointService.awardForInvite(invite.getInviter().getUsername(), newUserName); pointService.awardForInvite(invite.getInviter().getUsername(), newUserName);