/*
* Symphony - A modern community (forum/SNS/blog) platform written in Java.
* Copyright (C) 2012-2017, b3log.org & hacpai.com
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.b3log.symphony.service;
import org.apache.commons.lang.StringUtils;
import org.b3log.latke.Keys;
import org.b3log.latke.ioc.inject.Inject;
import org.b3log.latke.logging.Level;
import org.b3log.latke.logging.Logger;
import org.b3log.latke.model.Pagination;
import org.b3log.latke.repository.*;
import org.b3log.latke.service.ServiceException;
import org.b3log.latke.service.annotation.Service;
import org.b3log.latke.util.CollectionUtils;
import org.b3log.latke.util.Paginator;
import org.b3log.symphony.model.Domain;
import org.b3log.symphony.model.Tag;
import org.b3log.symphony.repository.DomainRepository;
import org.b3log.symphony.repository.DomainTagRepository;
import org.b3log.symphony.repository.TagRepository;
import org.b3log.symphony.util.Markdowns;
import org.json.JSONArray;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Domain query service.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.0.0.2, Mar 30, 2017
* @since 1.4.0
*/
@Service
public class DomainQueryService {
/**
* Logger.
*/
private static final Logger LOGGER = Logger.getLogger(DomainQueryService.class.getName());
/**
* Domain repository.
*/
@Inject
private DomainRepository domainRepository;
/**
* Tag repository.
*/
@Inject
private TagRepository tagRepository;
/**
* Domain tag repository.
*/
@Inject
private DomainTagRepository domainTagRepository;
/**
* Short link query service.
*/
@Inject
private ShortLinkQueryService shortLinkQueryService;
/**
* Gets most tag domain.
*
* @param fetchSize the specified fetch size
* @return domains, returns an empty list if not found
*/
public List<JSONObject> getMostTagDomain(final int fetchSize) {
final Query query = new Query().addSort(Domain.DOMAIN_SORT, SortDirection.ASCENDING).
addSort(Domain.DOMAIN_TAG_COUNT, SortDirection.DESCENDING).
addSort(Keys.OBJECT_ID, SortDirection.DESCENDING).
setPageSize(fetchSize).setPageCount(1);
try {
final List<JSONObject> ret = CollectionUtils.jsonArrayToList(domainRepository.get(query).optJSONArray(Keys.RESULTS));
for (final JSONObject domain : ret) {
final List<JSONObject> tags = getTags(domain.optString(Keys.OBJECT_ID));
domain.put(Domain.DOMAIN_T_TAGS, (Object) tags);
}
return ret;
} catch (final Exception e) {
LOGGER.log(Level.ERROR, "Gets most tag domain error", e);
return Collections.emptyList();
}
}
/**
* Gets a domain's tags.
*
* @param domainId the specified domain id
* @return tags, returns an empty list if not found
*/
public List<JSONObject> getTags(final String domainId) {
final List<JSONObject> ret = new ArrayList<JSONObject>();
final Query query = new Query().
setFilter(new PropertyFilter(Domain.DOMAIN + "_" + Keys.OBJECT_ID, FilterOperator.EQUAL, domainId));
try {
final List<JSONObject> relations = CollectionUtils.jsonArrayToList(
domainTagRepository.get(query).optJSONArray(Keys.RESULTS));
for (final JSONObject relation : relations) {
final String tagId = relation.optString(Tag.TAG + "_" + Keys.OBJECT_ID);
final JSONObject tag = tagRepository.get(tagId);
ret.add(tag);
}
} catch (final RepositoryException e) {
LOGGER.log(Level.ERROR, "Gets domain [id=" + domainId + "] tags error", e);
}
return ret;
}
/**
* Gets a domain by the specified domain URI.
*
* @param domainURI the specified domain URI
* @return domain, returns {@code null} if not null
* @throws ServiceException service exception
*/
public JSONObject getByURI(final String domainURI) throws ServiceException {
try {
final JSONObject ret = domainRepository.getByURI(domainURI);
if (null == ret) {
return null;
}
if (Domain.DOMAIN_STATUS_C_VALID != ret.optInt(Domain.DOMAIN_STATUS)) {
return null;
}
String description = ret.optString(Domain.DOMAIN_DESCRIPTION);
String descriptionText = ret.optString(Domain.DOMAIN_TITLE);
if (StringUtils.isNotBlank(description)) {
description = shortLinkQueryService.linkTag(description);
description = Markdowns.toHTML(description);
ret.put(Domain.DOMAIN_DESCRIPTION, description);
descriptionText = Jsoup.parse(description).text();
}
final String domainTitle = ret.optString(Domain.DOMAIN_TITLE);
if (StringUtils.isBlank(ret.optString(Domain.DOMAIN_SEO_TITLE))) {
ret.put(Domain.DOMAIN_SEO_TITLE, domainTitle);
}
if (StringUtils.isBlank(ret.optString(Domain.DOMAIN_SEO_DESC))) {
ret.put(Domain.DOMAIN_SEO_DESC, descriptionText);
}
if (StringUtils.isBlank(ret.optString(Domain.DOMAIN_SEO_KEYWORDS))) {
ret.put(Domain.DOMAIN_SEO_KEYWORDS, domainTitle);
}
return ret;
} catch (final RepositoryException e) {
LOGGER.log(Level.ERROR, "Gets domain [URI=" + domainURI + "] failed", e);
throw new ServiceException(e);
}
}
/**
* Gets a domain by the specified domain title.
*
* @param domainTitle the specified domain title
* @return domain, returns {@code null} if not null
* @throws ServiceException service exception
*/
public JSONObject getByTitle(final String domainTitle) throws ServiceException {
try {
final JSONObject ret = domainRepository.getByTitle(domainTitle);
if (null == ret) {
return null;
}
if (Domain.DOMAIN_STATUS_C_VALID != ret.optInt(Domain.DOMAIN_STATUS)) {
return null;
}
String description = ret.optString(Domain.DOMAIN_DESCRIPTION);
String descriptionText = ret.optString(Domain.DOMAIN_TITLE);
if (StringUtils.isNotBlank(description)) {
description = shortLinkQueryService.linkTag(description);
description = Markdowns.toHTML(description);
ret.put(Domain.DOMAIN_DESCRIPTION, description);
descriptionText = Jsoup.parse(description).text();
}
if (StringUtils.isBlank(ret.optString(Domain.DOMAIN_SEO_TITLE))) {
ret.put(Domain.DOMAIN_SEO_TITLE, domainTitle);
}
if (StringUtils.isBlank(ret.optString(Domain.DOMAIN_SEO_DESC))) {
ret.put(Domain.DOMAIN_SEO_DESC, descriptionText);
}
if (StringUtils.isBlank(ret.optString(Domain.DOMAIN_SEO_KEYWORDS))) {
ret.put(Domain.DOMAIN_SEO_KEYWORDS, domainTitle);
}
return ret;
} catch (final RepositoryException e) {
LOGGER.log(Level.ERROR, "Gets domain [title=" + domainTitle + "] failed", e);
throw new ServiceException(e);
}
}
/**
* Gets domains by the specified request json object.
*
* @param requestJSONObject the specified request json object, for example, <pre>
* {
* "domainTitle": "", // optional
* "paginationCurrentPageNum": 1,
* "paginationPageSize": 20,
* "paginationWindowSize": 10
* }, see {@link Pagination} for more details
* </pre>
*
* @param domainFields the specified domain fields to return
*
* @return for example, <pre>
* {
* "pagination": {
* "paginationPageCount": 100,
* "paginationPageNums": [1, 2, 3, 4, 5]
* },
* "domains": [{
* "oId": "",
* "domainTitle": "",
* "domainDescription": "",
* ....
* }, ....]
* }
* </pre>
*
* @throws ServiceException service exception
* @see Pagination
*/
public JSONObject getDomains(final JSONObject requestJSONObject, final Map<String, Class<?>> domainFields) throws ServiceException {
final JSONObject ret = new JSONObject();
final int currentPageNum = requestJSONObject.optInt(Pagination.PAGINATION_CURRENT_PAGE_NUM);
final int pageSize = requestJSONObject.optInt(Pagination.PAGINATION_PAGE_SIZE);
final int windowSize = requestJSONObject.optInt(Pagination.PAGINATION_WINDOW_SIZE);
final Query query = new Query().setCurrentPageNum(currentPageNum).setPageSize(pageSize).
addSort(Domain.DOMAIN_SORT, SortDirection.ASCENDING).
addSort(Domain.DOMAIN_TAG_COUNT, SortDirection.DESCENDING).
addSort(Keys.OBJECT_ID, SortDirection.DESCENDING);
for (final Map.Entry<String, Class<?>> field : domainFields.entrySet()) {
query.addProjection(field.getKey(), field.getValue());
}
if (requestJSONObject.has(Domain.DOMAIN_TITLE)) {
query.setFilter(new PropertyFilter(Domain.DOMAIN_TITLE, FilterOperator.EQUAL, requestJSONObject.optString(Domain.DOMAIN_TITLE)));
}
JSONObject result = null;
try {
result = domainRepository.get(query);
} catch (final RepositoryException e) {
LOGGER.log(Level.ERROR, "Gets domains failed", e);
throw new ServiceException(e);
}
final int pageCount = result.optJSONObject(Pagination.PAGINATION).optInt(Pagination.PAGINATION_PAGE_COUNT);
final JSONObject pagination = new JSONObject();
ret.put(Pagination.PAGINATION, pagination);
final List<Integer> pageNums = Paginator.paginate(currentPageNum, pageSize, pageCount, windowSize);
pagination.put(Pagination.PAGINATION_PAGE_COUNT, pageCount);
pagination.put(Pagination.PAGINATION_PAGE_NUMS, pageNums);
final JSONArray data = result.optJSONArray(Keys.RESULTS);
final List<JSONObject> domains = CollectionUtils.<JSONObject>jsonArrayToList(data);
ret.put(Domain.DOMAINS, domains);
return ret;
}
/**
* Gets a domain by the specified id.
*
* @param domainId the specified id
* @return a domain, return {@code null} if not found
* @throws ServiceException service exception
*/
public JSONObject getDomain(final String domainId) throws ServiceException {
try {
final JSONObject ret = domainRepository.get(domainId);
final List<JSONObject> tags = getTags(domainId);
ret.put(Domain.DOMAIN_T_TAGS, (Object) tags);
return ret;
} catch (final RepositoryException e) {
LOGGER.log(Level.ERROR, "Gets a domain [domainId=" + domainId + "] failed", e);
throw new ServiceException(e);
}
}
/**
* Whether a tag specified by the given tag title in a domain specified by the given domain id.
*
* @param tagTitle the given tag title
* @param domainId the given domain id
* @return {@code true} if the tag in the domain, returns {@code false} otherwise
*/
public boolean containTag(final String tagTitle, final String domainId) {
try {
final JSONObject domain = domainRepository.get(domainId);
if (null == domain) {
return true;
}
final JSONObject tag = tagRepository.getByTitle(tagTitle);
if (null == tag) {
return true;
}
final Query query = new Query().setFilter(
CompositeFilterOperator.and(
new PropertyFilter(Domain.DOMAIN + "_" + Keys.OBJECT_ID, FilterOperator.EQUAL, domainId),
new PropertyFilter(Tag.TAG + "_" + Keys.OBJECT_ID, FilterOperator.EQUAL, tag.optString(Keys.OBJECT_ID))));
return domainTagRepository.count(query) > 0;
} catch (final Exception e) {
LOGGER.log(Level.ERROR, "Check domain tag [tagTitle=" + tagTitle + ", domainId=" + domainId + "] failed", e);
return true;
}
}
}