package io.kaif.model.account;
import java.time.Instant;
import java.util.EnumSet;
import java.util.Set;
import java.util.UUID;
import javax.annotation.concurrent.Immutable;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import io.kaif.kmark.KmarkProcessor;
@Immutable
public class Account implements Authorization {
public static final int PASSWORD_MIN = 6;
public static final int PASSWORD_MAX = 100;
public static final int NAME_MIN = 3;
public static final int NAME_MAX = 15;
//changing pattern should review sign_up_form.dart, Emitter.java
public static final String NAME_PATTERN = "^[a-zA-Z_0-9]{3,15}$";
public static Account create(String username,
String email,
String passwordHash,
Instant createTime) {
return new Account(UUID.randomUUID(),
username,
email,
passwordHash,
"",
createTime,
EnumSet.of(Authority.TOURIST));
}
public static boolean isValidPassword(String password) {
return password != null
&& password.length() >= PASSWORD_MIN
&& password.length() <= PASSWORD_MAX;
}
public static boolean isValidUsername(String username) {
return username != null
&& username.length() >= NAME_MIN
&& username.length() <= NAME_MAX
&& username.matches(NAME_PATTERN)
&& !username.equalsIgnoreCase("null");
}
public static String renderDescriptionPreview(String description) {
return KmarkProcessor.process(description);
}
private final String username;
private final UUID accountId;
private final String email;
private final String passwordHash;
private final String description;
private final Instant createTime;
private final Set<Authority> authorities;
Account(UUID accountId,
String username,
String email,
String passwordHash,
String description,
Instant createTime,
Set<Authority> authorities) {
this.username = username;
this.accountId = accountId;
this.description = description;
this.email = email;
this.passwordHash = passwordHash;
this.createTime = createTime;
this.authorities = authorities;
}
public String getUsername() {
return username;
}
public UUID getAccountId() {
return accountId;
}
public String getEmail() {
return email;
}
public String getPasswordHash() {
return passwordHash;
}
public Instant getCreateTime() {
return createTime;
}
/**
* do not include password hash in toString
*/
public Set<Authority> getAuthorities() {
return authorities;
}
/**
* equals and hashCode use `username` instead of accountId for easier testing.
* username is unique so it is safe
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Account account = (Account) o;
if (username != null ? !username.equals(account.username) : account.username != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
return username != null ? username.hashCode() : 0;
}
public boolean isActivated() {
return authorities.contains(Authority.CITIZEN);
}
@Override
public String toString() {
return "Account{" +
"username='" + username + '\'' +
", accountId=" + accountId +
", email='" + email + '\'' +
", description='" + description + '\'' +
", createTime=" + createTime +
", authorities=" + authorities +
'}';
}
@Override
public UUID authenticatedId() {
return accountId;
}
@Override
public boolean containsAuthority(Authority authority) {
return authorities.contains(authority);
}
@Override
public boolean matches(Account account) {
return authenticatedId().equals(account.getAccountId())
&& passwordHash.equals(account.getPasswordHash())
&& authorities.equals(account.getAuthorities());
}
public Account withAuthorities(Set<Authority> authorities) {
Preconditions.checkArgument(!authorities.contains(Authority.FORBIDDEN));
return new Account(accountId,
username,
email,
passwordHash,
description,
createTime,
authorities);
}
public String getRenderDescription() {
//username as anchor prefix
return KmarkProcessor.process(description);
}
public String getDescription() {
return description;
}
public String getEscapedDescription() {
return KmarkProcessor.escapeHtml(description);
}
@VisibleForTesting
public Account withPasswordHash(String newPasswordHash) {
return new Account(accountId,
username,
email,
newPasswordHash,
description,
createTime,
authorities);
}
}