package gov.nysenate.openleg.dao.auth;
import gov.nysenate.openleg.dao.base.ImmutableParams;
import gov.nysenate.openleg.dao.base.SqlBaseDao;
import gov.nysenate.openleg.model.auth.ApiUser;
import gov.nysenate.openleg.service.auth.OpenLegRole;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.stereotype.Repository;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Repository
public class SqlApiUserDao extends SqlBaseDao implements ApiUserDao
{
public static final Logger logger = LoggerFactory.getLogger(SqlApiUserDao.class);
/** {@inheritDoc} */
@Override
public void insertUser (ApiUser user) throws DataAccessException {
if (jdbcNamed.update(ApiUserQuery.UPDATE_API_USER.getSql(schema()), getUserParams(user)) == 0)
jdbcNamed.update(ApiUserQuery.INSERT_API_USER.getSql(schema()), getUserParams(user));
}
/** {@inheritDoc} */
@Override
public void updateUser(ApiUser user) throws DataAccessException {
jdbcNamed.update(ApiUserQuery.UPDATE_API_USER.getSql(schema()), getUserParams(user));
}
/** {@inheritDoc} */
@Override
public List<ApiUser> getAllUsers() throws DataAccessException {
ApiUserRowHandler rowHandler = new ApiUserRowHandler();
jdbcNamed.query(ApiUserQuery.SELECT_API_USERS.getSql(schema()), new MapSqlParameterSource(), rowHandler);
return rowHandler.getUsers();
}
/** {@inheritDoc} */
@Override
public ApiUser getApiUserFromEmail(String email_addr) throws DataAccessException {
ImmutableParams params = ImmutableParams.from(new MapSqlParameterSource("email", email_addr));
ApiUserRowHandler rowHandler = new ApiUserRowHandler();
jdbcNamed.query(ApiUserQuery.SELECT_BY_EMAIL.getSql(schema()), params, rowHandler);
return rowHandler.getSingleUser();
}
/** {@inheritDoc} */
@Override
public ApiUser getApiUserFromKey(String key) {
ImmutableParams params = ImmutableParams.from(new MapSqlParameterSource("apikey", key));
ApiUserRowHandler rowHandler = new ApiUserRowHandler();
jdbcNamed.query(ApiUserQuery.SELECT_BY_KEY.getSql(schema()), params, rowHandler);
return rowHandler.getSingleUser();
}
/** {@inheritDoc} */
@Override
public ApiUser getApiUserFromToken(String token) {
MapSqlParameterSource params = new MapSqlParameterSource("registrationToken", token);
ApiUserRowHandler rowHandler = new ApiUserRowHandler();
jdbcNamed.query(ApiUserQuery.SELECT_BY_TOKEN.getSql(schema()), params, rowHandler);
return rowHandler.getSingleUser();
}
/** {@inheritDoc} */
@Override
public void deleteApiUser(ApiUser user) throws DataAccessException {
jdbcNamed.update(ApiUserQuery.DELETE_USER.getSql(schema()), getUserParams(user));
}
/** {@inheritDoc} */
@Override
public void grantRole(String apiKey, OpenLegRole role) {
try {
jdbcNamed.update(ApiUserQuery.INSERT_API_USER_ROLE.getSql(schema()), getRoleParams(apiKey, role));
} catch (DuplicateKeyException ignored) {}
}
/** {@inheritDoc} */
@Override
public void revokeRole(String apiKey, OpenLegRole role) {
jdbcNamed.update(ApiUserQuery.DELETE_API_USER_ROLE.getSql(schema()), getRoleParams(apiKey, role));
}
/** --- Internal Methods --- */
protected MapSqlParameterSource getUserParams(ApiUser user) {
return new MapSqlParameterSource()
.addValue("apikey", user.getApiKey())
.addValue("authenticated", user.isAuthenticated())
.addValue("apiRequests", user.getNumApiRequests())
.addValue("email", user.getEmail())
.addValue("name", user.getName())
.addValue("organizationName", user.getOrganizationName())
.addValue("registrationToken", user.getRegistrationToken());
}
protected MapSqlParameterSource getRoleParams(String apiKey, OpenLegRole role) {
return new MapSqlParameterSource()
.addValue("apiKey", apiKey)
.addValue("role", role.name());
}
private static final RowMapper <ApiUser> apiUserMapper = (rs, rowNum) -> {
ApiUser user = new ApiUser(rs.getString("email_addr"));
user.setAuthenticated(rs.getBoolean("authenticated"));
user.setName(rs.getString("users_name"));
user.setRegistrationToken(rs.getString("reg_token"));
user.setApiKey(rs.getString("apikey"));
user.setOrganizationName(rs.getString("org_name"));
return user;
};
private static final class ApiUserRowHandler implements RowCallbackHandler
{
private final Map<String, ApiUser> apiUserMap = new LinkedHashMap<>();
@Override
public void processRow(ResultSet rs) throws SQLException {
String apiKey = rs.getString("apikey");
if (!apiUserMap.containsKey(apiKey)) {
apiUserMap.put(apiKey, apiUserMapper.mapRow(rs, rs.getRow()));
}
String roleStr = rs.getString("role");
if (roleStr != null) {
apiUserMap.get(apiKey).addRole(OpenLegRole.valueOf(roleStr));
}
}
public List<ApiUser> getUsers() {
return new ArrayList<>(apiUserMap.values());
}
public ApiUser getSingleUser() {
if (apiUserMap.size() > 1) {
throw new IncorrectResultSizeDataAccessException(1, apiUserMap.size());
}
return apiUserMap.values().stream().findAny()
.orElseThrow(() -> new EmptyResultDataAccessException(1));
}
}
}