package io.kaif.model.clientapp;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;
import io.kaif.database.DaoOperations;
import io.kaif.model.account.Account;
@Repository
public class ClientAppDao implements DaoOperations {
private static final String FIND_CLIENT_APP_USER_CACHE_NAME = "findClientAppUser";
@Autowired
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
private final RowMapper<ClientApp> clientAppMapper = (rs, num) -> {
return new ClientApp(rs.getString("clientId"),
rs.getString("clientSecret"),
rs.getString("appName"),
rs.getString("description"),
rs.getTimestamp("createTime").toInstant(),
UUID.fromString(rs.getString("ownerAccountId")),
rs.getBoolean("revoked"),
rs.getString("callbackUri"));
};
private final RowMapper<ClientAppUser> clientAppUserMapper = (rs, num) -> {
Set<ClientAppScope> lastGrantedScopes = convertVarcharArray(rs.getArray("lastGrantedScopes")).map(
ClientAppScope::valueOf).collect(Collectors.toSet());
return new ClientAppUser(UUID.fromString(rs.getString("clientAppUserId")),
rs.getString("clientId"),
rs.getString("clientSecret"),
UUID.fromString(rs.getString("accountId")),
lastGrantedScopes,
rs.getTimestamp("lastUpdateTime").toInstant());
};
@Override
public NamedParameterJdbcTemplate namedJdbc() {
return namedParameterJdbcTemplate;
}
public ClientApp createApp(Account creator,
String name,
String description,
String callbackUri,
Instant now) {
ClientApp app = ClientApp.create(creator.authenticatedId(),
name,
description,
callbackUri,
now);
jdbc().update(""
+ " INSERT "
+ " INTO ClientApp "
+ " (clientId, clientSecret, appName, description, createTime, "
+ " ownerAccountId, revoked, callbackUri) "
+ " VALUES "
+ questions(8),
app.getClientId(),
app.getClientSecret(),
app.getAppName(),
app.getDescription(),
Timestamp.from(app.getCreateTime()),
app.getOwnerAccountId(),
app.isRevoked(),
app.getCallbackUri());
return app;
}
public ClientApp loadAppWithoutCache(String clientId) {
return jdbc().queryForObject(" SELECT * FROM ClientApp WHERE clientId = ? ",
clientAppMapper,
clientId);
}
public List<ClientApp> listAppOrderByTime(UUID ownerAccountId) {
return jdbc().query(" SELECT * FROM ClientApp WHERE ownerAccountId = ? ORDER BY createTime ",
clientAppMapper,
ownerAccountId);
}
public void updateAppInformation(ClientApp updated) {
jdbc().update(""
+ " UPDATE ClientApp "
+ " SET appName = ? "
+ " , description = ? "
+ " , revoked = ? "
+ " , callbackUri = ? "
+ " WHERE clientId = ? ",
updated.getAppName(),
updated.getDescription(),
updated.isRevoked(),
updated.getCallbackUri(),
updated.getClientId());
}
/*
* there is no way to evict app's all users, so we have to evict all entries
*/
@CacheEvict(value = FIND_CLIENT_APP_USER_CACHE_NAME, allEntries = true)
public void updateAppSecret(ClientApp updated) {
jdbc().update("" + " UPDATE ClientApp " + " SET clientSecret = ? " + " WHERE clientId = ? ",
updated.getClientSecret(),
updated.getClientId());
}
public Optional<ClientApp> findApp(String clientId) {
return jdbc().query(" SELECT * FROM ClientApp WHERE clientId = ? LIMIT 1",
clientAppMapper,
clientId).stream().findAny();
}
@CacheEvict(value = FIND_CLIENT_APP_USER_CACHE_NAME, key = "#a0.accountId + #a1.clientId")
public ClientAppUser mergeClientAppUser(Account account,
ClientApp clientApp,
Set<ClientAppScope> scopes,
Instant now) {
Optional<ClientAppUser> exist = findClientAppUserWithoutCache(account.getAccountId(),
clientApp.getClientId());
if (exist.isPresent()) {
ClientAppUser updated = exist.get()
.withScopes(scopes)
.withLastUpdateTime(now)
.withClientSecret(clientApp.getClientSecret());
jdbc().update(""
+ " UPDATE ClientAppUser "
+ " SET lastGrantedScopes = ? "
+ " , lastUpdateTime = ? "
+ " WHERE clientAppUserId = ? ",
createVarcharArray(updated.getLastGrantedScopes().stream().map(ClientAppScope::name)),
Timestamp.from(updated.getLastUpdateTime()),
updated.getClientAppUserId());
return updated;
} else {
ClientAppUser created = ClientAppUser.create(clientApp.getClientId(),
clientApp.getClientSecret(),
account.getAccountId(),
scopes,
now);
jdbc().update(""
+ " INSERT "
+ " INTO ClientAppUser "
+ " (clientAppUserId, clientId, accountId, lastGrantedScopes, lastUpdateTime )"
+ " VALUES "
+ questions(5),
created.getClientAppUserId(),
created.getClientId(),
created.getAccountId(),
createVarcharArray(created.getLastGrantedScopes().stream().map(ClientAppScope::name)),
Timestamp.from(created.getLastUpdateTime()));
return created;
}
}
@Cacheable(value = FIND_CLIENT_APP_USER_CACHE_NAME, key = "#a0 + #a1")
public Optional<ClientAppUser> findClientAppUserWithCache(UUID accountId, String clientId) {
return findClientAppUserWithoutCache(accountId, clientId);
}
public Optional<ClientAppUser> findClientAppUserWithoutCache(UUID accountId, String clientId) {
return jdbc().query(""
+ " SELECT cau.*, ClientApp.clientSecret "
+ " FROM ClientAppUser cau "
+ " JOIN ClientApp ON (cau.clientId = ClientApp.clientId ) "
+ " WHERE cau.accountId = ? "
+ " AND cau.clientId = ? "
+ " LIMIT 1 ", clientAppUserMapper, accountId, clientId).stream().findAny();
}
public List<ClientAppUser> listUsers(UUID accountId) {
return jdbc().query(""
+ " SELECT cau.*, ClientApp.clientSecret "
+ " FROM ClientAppUser cau "
+ " JOIN ClientApp ON (cau.clientId = ClientApp.clientId ) "
+ " WHERE cau.accountId = ? ", clientAppUserMapper, accountId);
}
@CacheEvict(value = FIND_CLIENT_APP_USER_CACHE_NAME, key = "#a0 + #a1")
public void deleteClientAppUser(UUID accountId, String clientId) {
jdbc().update(""
+ " DELETE "
+ " FROM ClientAppUser "
+ " WHERE accountId = ? "
+ " AND clientId = ? ", accountId, clientId);
}
public List<ClientApp> listAppsByUser(UUID accountId) {
return jdbc().query(""
+ " SELECT ClientApp.* "
+ " FROM ClientAppUser cau "
+ " JOIN ClientApp ON (cau.clientId = ClientApp.clientId ) "
+ " WHERE cau.accountId = ? "
+ " ORDER BY cau.lastUpdateTime DESC ", clientAppMapper, accountId);
}
}