/* * Copyright 1998-2017 Linux.org.ru * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ru.org.linux.topic; import com.google.common.collect.Sets; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; import javax.sql.DataSource; import java.util.*; @Repository public class TopicListDao { private static final Logger logger = LoggerFactory.getLogger(TopicListDao.class); private JdbcTemplate jdbcTemplate; private NamedParameterJdbcTemplate namedJdbcTemplate; @Autowired public void setDataSource(DataSource ds) { jdbcTemplate = new JdbcTemplate(ds); namedJdbcTemplate = new NamedParameterJdbcTemplate(ds); } public List<Topic> getTopics(TopicListDto topicListDto) { logger.debug("TopicListDao.getTopics(); topicListDto = " + topicListDto.toString()); Map<String, Object> params = new HashMap<>(); String sort = makeSortOrder(topicListDto); String limit = makeLimitAndOffset(topicListDto); StringBuilder query = new StringBuilder(); query .append("SELECT ") .append("postdate, topics.id as msgid, topics.userid, topics.title, ") .append("topics.groupid as guid, topics.url, topics.linktext, ua_id, ") .append("urlname, section, topics.sticky, topics.postip, ") .append("postdate<(CURRENT_TIMESTAMP-sections.expire) as expired, deleted, lastmod, commitby, ") .append("commitdate, topics.stat1, postscore, topics.moderate, notop, ") .append("topics.resolved, minor, draft ") .append("FROM topics ") .append("INNER JOIN groups ON (groups.id=topics.groupid) ") .append("INNER JOIN sections ON (sections.id=groups.section) "); if (topicListDto.isUserFavs()) { query.append("INNER JOIN memories ON (memories.topic = topics.id) "); } query .append("WHERE ") .append(makeConditions(topicListDto, params)) .append(sort) .append(limit); logger.trace("SQL query: " + query); return namedJdbcTemplate.query( query.toString(), params, (resultSet, i) -> new Topic(resultSet) ); } /** * Возвращает удаленные темы в премодерируемом разделе. * * Темы, удаленные автором пропускаются. * * @param sectionId номер раздела или 0 для всех премодерируемых * @param skipEmptyReason Пропускать темы, удаленные с пустым комментарием * @return список удаленных тем */ public List<TopicListDto.DeletedTopic> getDeletedTopics(int sectionId, boolean skipEmptyReason) { StringBuilder query = new StringBuilder(); List <Object> queryParameters = new ArrayList<>(); query .append("SELECT ") .append("topics.title as subj, nick, groups.section, topics.id as msgid, ") .append("reason, topics.postdate, del_info.delDate ") .append("FROM topics,groups,users,sections,del_info ") .append("WHERE sections.id=groups.section AND topics.userid=users.id ") .append("AND topics.groupid=groups.id AND sections.moderate AND deleted ") .append("AND del_info.msgid=topics.id AND topics.userid!=del_info.delby ") .append("AND delDate is not null "); if (skipEmptyReason) { query.append("AND reason!='' "); } if (sectionId != 0) { query.append(" AND section=? "); queryParameters.add(sectionId); } query.append(" ORDER BY del_info.delDate DESC LIMIT 20"); return jdbcTemplate.query( query.toString(), queryParameters.toArray(), (rs, rowNum) -> new TopicListDto.DeletedTopic(rs) ); } /** * Создание условий выборки SQL-запроса. * * @param request объект, содержащий условия выборки * @return строка, содержащая условия выборки SQL-запроса */ private static CharSequence makeConditions(TopicListDto request, Map<String, Object> paramsBuilder) { StringBuilder where = new StringBuilder("NOT deleted"); where.append(request.getCommitMode().getQueryPiece()); Set<Integer> sections = Sets.filter(request.getSections(), v -> v != 0); if (!sections.isEmpty()) { where.append(" AND section in (:sections)"); paramsBuilder.put("sections", sections); } if (request.getGroup() != 0) { where.append(" AND groupid=:groupId"); paramsBuilder.put("groupId", request.getGroup()); } switch (request.getDateLimitType()) { case BETWEEN: where.append(" AND postdate>=:fromDate AND postdate<:toDate"); paramsBuilder.put("fromDate", request.getFromDate()); paramsBuilder.put("toDate", request.getToDate()); break; case FROM_DATE: where.append(" AND postdate>=:fromDate"); paramsBuilder.put("fromDate", request.getFromDate()); break; default: } if (request.getUserId() != 0) { paramsBuilder.put("userId", request.getUserId()); if (request.isUserFavs()) { where.append(" AND memories.userid=:userId"); } else { where.append(" AND userid=:userId"); } if (request.isUserFavs()) { if (request.isUserWatches()) { where.append(" AND watch "); } else { where.append(" AND NOT watch "); } } } if (request.isNotalks()) { where.append(" AND not topics.groupid=8404"); } if (request.isTech()) { where.append(" AND not topics.groupid=8404 AND not topics.groupid=4068 AND groups.section=2"); } switch (request.getMiniNewsMode()) { case MAJOR: where.append(" AND NOT minor"); break; case MINOR: where.append(" AND minor"); break; } if (request.getTag() != 0) { paramsBuilder.put("tagId", request.getTag()); where.append(" AND topics.id IN (SELECT msgid FROM tags WHERE tagid=:tagId)"); } if (!request.isShowDraft()) { where.append(" AND NOT topics.draft "); } else { where.append(" AND topics.draft "); } return where; } /** * Создание условий сортировки SQL-запроса. * * @param topicListDto объект, содержащий условия выборки * @return строка, содержащая условия сортировки */ private static String makeSortOrder(TopicListDto topicListDto) { if (topicListDto.isLastmodSort()) { return "ORDER BY lastmod DESC"; } if (topicListDto.isUserFavs()) { return "ORDER BY memories.id DESC"; } switch (topicListDto.getCommitMode()) { case COMMITED_ONLY: return " ORDER BY commitdate DESC"; case UNCOMMITED_ONLY: return " ORDER BY postdate DESC"; case POSTMODERATED_ONLY: return " ORDER BY postdate DESC"; default: return " ORDER BY COALESCE(commitdate, postdate) DESC"; } } /** * Создание ограничений размера результатов SQL-запроса. * * @param topicListDto объект, содержащий условия выборки * @return строка, содержащая смещение и количество записей */ private static String makeLimitAndOffset(TopicListDto topicListDto) { String limitStr = ""; if (topicListDto.getLimit() != null) { limitStr += " LIMIT " + topicListDto.getLimit().toString(); } if (topicListDto.getOffset() != null) { limitStr += " OFFSET " + topicListDto.getOffset().toString(); } return limitStr; } public enum CommitMode { COMMITED_ONLY(" AND sections.moderate AND commitdate is not null "), UNCOMMITED_ONLY(" AND (NOT topics.moderate) AND sections.moderate "), POSTMODERATED_ONLY(" AND NOT sections.moderate"), COMMITED_AND_POSTMODERATED(" AND (topics.moderate OR NOT sections.moderate) "), ALL(" "); private final String queryPiece; CommitMode(String queryPiece) { this.queryPiece = queryPiece; } public String getQueryPiece() { return queryPiece; } } }