/** * This file is part of lavagna. * * lavagna is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * lavagna is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with lavagna. If not, see <http://www.gnu.org/licenses/>. */ package io.lavagna.service; import io.lavagna.common.Json; import io.lavagna.model.*; import io.lavagna.model.util.CalendarTokenNotFoundException; import io.lavagna.query.UserQuery; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.RowCallbackHandler; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; import static org.apache.commons.lang3.StringUtils.trimToNull; /** * CRUD operation over {@link User} */ @Repository @Transactional(readOnly = true) public class UserRepository { private final NamedParameterJdbcTemplate jdbc; private final UserQuery queries; public UserRepository(NamedParameterJdbcTemplate jdbc, UserQuery queries) { this.jdbc = jdbc; this.queries = queries; } public User findUserByName(String provider, String name) { return queries.findUserByName(provider, name); } public User findById(int id) { return queries.findUserById(id); } public List<User> findByIds(Collection<Integer> ids) { return ids.isEmpty() ? Collections.<User>emptyList() : queries.findByIds(ids); } public boolean userExistsAndEnabled(String provider, String name) { return !Integer.valueOf(0).equals(queries.userExistsAndEnabled(provider, name, true)); } public boolean userExists(String provider, String name) { return !Integer.valueOf(0).equals(queries.userExistsAndEnabled(provider, name)); } public List<User> findUsers(String criteria) { return queries.findUsers(criteria); } /** * Find users that have access to specific project * * @param criteria * @param projectId * @param permission * @return */ public List<User> findUsers(String criteria, int projectId, Permission permission) { return queries.findUsers(criteria, projectId, permission.toString());// } @Transactional(readOnly = false) public void createUsers(Collection<User> users) { List<SqlParameterSource> params = new ArrayList<>(users.size()); for (User user : users) { params.add(prepareUserParameterSource(user)); } jdbc.batchUpdate(queries.createUserFull(), params.toArray(new SqlParameterSource[params.size()])); } private static SqlParameterSource prepareUserParameterSource(User user) { return new MapSqlParameterSource("provider", trimToNull(user.getProvider())) .addValue("userName", trimToNull(user.getUsername())).addValue("email", trimToNull(user.getEmail())) .addValue("displayName", trimToNull(user.getDisplayName())).addValue("enabled", user.getEnabled()) .addValue("emailNotification", user.getEmailNotification()) .addValue("memberSince", ObjectUtils.firstNonNull(user.getMemberSince(), new Date())) .addValue("skipOwnNotifications", user.getSkipOwnNotifications()) .addValue("metadata", user.getUserMetadataRaw()); } @Transactional(readOnly = false) public int createUser(String provider, String userName, String password, String email, String displayName, boolean enabled) { return queries.createUser(provider, userName, password, email, displayName, enabled); } @Transactional(readOnly = false) public int updateProfile(User user, String email, String displayName, boolean emailNotification, boolean skipOwnNotifications) { return queries.updateProfile(trimToNull(email), trimToNull(displayName), emailNotification, skipOwnNotifications, user.getId()); } @Transactional(readOnly = false) public int updateMetadata(int userId, UserMetadata metadata) { return queries.updateMetadata(Json.GSON.toJson(metadata), userId); } @Transactional(readOnly = false) public int toggle(int userId, boolean enabled) { return queries.toggle(enabled, userId); } public List<User> findAll() { return queries.findAll(); } public Map<String, Integer> findUsersId(List<String> users) { List<String[]> usersToFind = new ArrayList<>(users.size()); for (String user : users) { String[] splittedString = StringUtils.split(user, ':'); if (splittedString.length > 1) { String provider = splittedString[0]; String username = StringUtils.join(ArrayUtils.subarray(splittedString, 1, splittedString.length), ':'); usersToFind.add(new String[] { provider, username }); } } if (usersToFind.isEmpty()) { return Collections.emptyMap(); } final Map<String, Integer> res = new HashMap<>(); MapSqlParameterSource param = new MapSqlParameterSource("users", usersToFind); jdbc.query(queries.findUsersId(), param, new RowCallbackHandler() { @Override public void processRow(ResultSet rs) throws SQLException { res.put(rs.getString("PROVIDER_USER"), rs.getInt("USER_ID")); } }); return res; } @Transactional(readOnly = false) public String createRememberMeToken(int userId) { String token = UUID.randomUUID().toString();// <- this use secure random String hashedToken = DigestUtils.sha256Hex(token); queries.registerRememberMeToken(hashedToken, userId, new Date()); return token; } @Transactional(readOnly = false) public void deleteRememberMeToken(int userId, String token) { queries.deleteToken(DigestUtils.sha256Hex(token), userId); } public boolean rememberMeTokenExists(int userId, String token) { String hashedToken = DigestUtils.sha256Hex(token); return queries.tokenExists(hashedToken, userId).equals(1); } @Transactional(readOnly = false) public void clearAllTokens(User user) { queries.deleteAllTokensForUserId(user.getId()); } public CalendarInfo findCalendarInfoFromUserId(User user) throws CalendarTokenNotFoundException { try { return queries.findCalendarInfoFromUserId(user.getId()); } catch (EmptyResultDataAccessException ex) { throw new CalendarTokenNotFoundException(); } } public int findUserIdFromCalendarToken(String token) { return queries.findUserIdFromCalendarToken(token); } @Transactional(readOnly = false) public int registerCalendarToken(User user, String token) { return queries.registerCalendarToken(user.getId(), token); } @Transactional(readOnly = false) public int deleteCalendarToken(User user) { return queries.deleteCalendarToken(user.getId()); } @Transactional(readOnly = false) public int setCalendarFeedDisabled(User user, boolean isDisabled) { return queries.setCalendarFeedDisabled(user.getId(), isDisabled); } public boolean isCalendarFeedDisabled(User user) { return queries.isCalendarFeedDisabled(user.getId()); } public String getHashedPassword(String provider, String username) { return queries.getHashedPassword(provider, username); } @Transactional(readOnly = false) public int setUserPassword(int userId, String hashedPassword) { return queries.setPassword(userId, hashedPassword); } public Map<String, String> findUsersWithPasswords() { Map<String, String> userWithPassword = new HashMap<>(); for(UserWithPassword uwp : queries.findUsersWithPasswords()) { userWithPassword.put(uwp.getUsername(), uwp.getPassword()); } return userWithPassword; } }