/*
This file is part of Cyclos (www.cyclos.org).
A project of the Social Trade Organisation (www.socialtrade.org).
Cyclos 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 2 of the License, or
(at your option) any later version.
Cyclos 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 Cyclos; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package nl.strohalm.cyclos.dao.members;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import nl.strohalm.cyclos.dao.IndexedDAOImpl;
import nl.strohalm.cyclos.dao.JDBCCallback;
import nl.strohalm.cyclos.entities.Relationship;
import nl.strohalm.cyclos.entities.access.Channel;
import nl.strohalm.cyclos.entities.accounts.Account;
import nl.strohalm.cyclos.entities.customization.fields.CustomFieldValue;
import nl.strohalm.cyclos.entities.customization.fields.MemberCustomField;
import nl.strohalm.cyclos.entities.exceptions.EntityNotFoundException;
import nl.strohalm.cyclos.entities.exceptions.QueryParseException;
import nl.strohalm.cyclos.entities.groups.BrokerGroup;
import nl.strohalm.cyclos.entities.groups.Group;
import nl.strohalm.cyclos.entities.groups.MemberGroup;
import nl.strohalm.cyclos.entities.members.AdminQuery;
import nl.strohalm.cyclos.entities.members.Administrator;
import nl.strohalm.cyclos.entities.members.Element;
import nl.strohalm.cyclos.entities.members.Element.Nature;
import nl.strohalm.cyclos.entities.members.ElementQuery;
import nl.strohalm.cyclos.entities.members.FullTextAdminQuery;
import nl.strohalm.cyclos.entities.members.FullTextElementQuery;
import nl.strohalm.cyclos.entities.members.FullTextMemberQuery;
import nl.strohalm.cyclos.entities.members.FullTextOperatorQuery;
import nl.strohalm.cyclos.entities.members.Member;
import nl.strohalm.cyclos.entities.members.MemberQuery;
import nl.strohalm.cyclos.entities.members.Operator;
import nl.strohalm.cyclos.entities.members.OperatorQuery;
import nl.strohalm.cyclos.entities.members.RegistrationAgreement;
import nl.strohalm.cyclos.entities.settings.LocalSettings;
import nl.strohalm.cyclos.entities.settings.LocalSettings.MemberResultDisplay;
import nl.strohalm.cyclos.entities.settings.LocalSettings.SortOrder;
import nl.strohalm.cyclos.services.elements.BrokerQuery;
import nl.strohalm.cyclos.services.settings.SettingsServiceLocal;
import nl.strohalm.cyclos.utils.EntityHelper;
import nl.strohalm.cyclos.utils.JDBCWrapper;
import nl.strohalm.cyclos.utils.Period;
import nl.strohalm.cyclos.utils.hibernate.HibernateCustomFieldHandler;
import nl.strohalm.cyclos.utils.hibernate.HibernateHelper;
import nl.strohalm.cyclos.utils.lucene.Filters;
import nl.strohalm.cyclos.utils.lucene.LuceneUtils;
import nl.strohalm.cyclos.utils.query.PageParameters;
import nl.strohalm.cyclos.utils.query.QueryParameters.ResultType;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.queryParser.MultiFieldQueryParser;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.hibernate.SQLQuery;
/**
* Implementation class for element DAO
* @author rafael
* @author luis
*/
public class ElementDAOImpl extends IndexedDAOImpl<Element> implements ElementDAO {
private static final String[] FIELDS_FULL_TEXT = { "name", "username", "email", "customValues" };
private HibernateCustomFieldHandler hibernateCustomFieldHandler;
private SettingsServiceLocal settingsService;
public ElementDAOImpl() {
super(Element.class);
}
@Override
public void activateMembersOfGroup(final MemberGroup group) {
final Map<String, Object> namedParameters = new HashMap<String, Object>();
namedParameters.put("date", Calendar.getInstance());
namedParameters.put("group", group);
bulkUpdate("update Member set activationDate = :date where group = :group and activationDate is null", namedParameters);
}
@Override
public void createAgreementForAllMembers(final RegistrationAgreement registrationAgreement, final MemberGroup group) {
runNative(new JDBCCallback() {
@Override
public void execute(final JDBCWrapper jdbc) throws SQLException {
final String insert = "insert into registration_agreement_logs (member_id, registration_agreement_id, date) select id, ?, ? from members where group_id = ?";
jdbc.execute(insert, registrationAgreement.getId(), Calendar.getInstance(), group.getId());
}
});
}
@Override
public List<? extends Element> fullTextSearch(final FullTextElementQuery elementQuery) {
final String keywords = StringUtils.trimToNull(elementQuery.getKeywords());
final Nature nature = elementQuery.getNature();
// We cannot search on a null nature
if (nature == null) {
return Collections.emptyList();
}
// When searching by keywords, use the full-text query
Analyzer analyzer = elementQuery.getAnalyzer();
Query query;
Sort sort = null;
if (keywords == null) {
query = new MatchAllDocsQuery();
sort = new Sort(new SortField("creationDate", SortField.STRING, true));
} else {
try {
query = keywords == null ? new MatchAllDocsQuery() : getQueryParser(analyzer).parse(keywords);
} catch (final ParseException e) {
throw new QueryParseException(e);
}
}
final Filters filters = new Filters();
filters.addTerms("active", elementQuery.getEnabled());
filters.addTerms("group", elementQuery.getGroups());
final Collection<? extends CustomFieldValue> customValues = elementQuery.getCustomValues();
if (CollectionUtils.isNotEmpty(customValues)) {
for (final CustomFieldValue fieldValue : customValues) {
addCustomField(filters, analyzer, fieldValue);
}
}
if (CollectionUtils.isNotEmpty(elementQuery.getExcludeElements())) {
Collection<Long> excludeIds = EntityHelper.toIdsAsList(elementQuery.getExcludeElements());
filters.add(Filters.andNot(Filters.terms("id", excludeIds)));
}
if (elementQuery instanceof FullTextMemberQuery) {
final FullTextMemberQuery memberQuery = (FullTextMemberQuery) elementQuery;
filters.addPeriod("activationDate", memberQuery.getActivationPeriod());
filters.addTerms("broker", memberQuery.getBroker());
if (memberQuery.isWithImagesOnly()) {
filters.addTerms("hasImages", true);
}
sort = decideSorting(memberQuery);
} else if (elementQuery instanceof FullTextOperatorQuery) {
final FullTextOperatorQuery operatorQuery = (FullTextOperatorQuery) elementQuery;
final Member member = operatorQuery.getMember();
if (member == null) {
// Cannot search operators without a member
return Collections.emptyList();
}
filters.addTerms("member", member);
} else if (elementQuery instanceof FullTextAdminQuery) {
sort = decideSorting(elementQuery);
}
return list(nature.getElementClass(), elementQuery, query, filters, sort);
}
@Override
public Map<Long, Integer> getCountPerGroup(final Collection<MemberGroup> groups) {
Map<String, ?> params = Collections.singletonMap("groups", groups);
StringBuilder hql = new StringBuilder();
hql.append(" select g.id, count(m.id) ");
hql.append(" from Member m join m.group g ");
hql.append(" where g in (:groups) ");
hql.append(" group by g.id ");
return this.<Long, Integer> map(hql.toString(), params);
}
@Override
public Map<Long, Integer> getCountPerGroup(final Collection<MemberGroup> groups, final Calendar timePoint) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("groups", groups);
params.put("timePoint", timePoint);
StringBuilder hql = new StringBuilder();
hql.append(" select g.id, count(m.id) ");
hql.append(" from GroupHistoryLog l join l.element m join l.group g ");
hql.append(" where g in (:groups) ");
hql.append(" and l.period.begin <= :timePoint ");
hql.append(" and (l.period.end is null or l.period.end > :timePoint)");
hql.append(" group by g.id");
return this.<Long, Integer> map(hql.toString(), params);
}
@Override
public Calendar getFirstMemberActivationDate() {
final String hql = "select min(activationDate) from Member";
return uniqueResult(hql, new HashMap<String, Object>());
}
public HibernateCustomFieldHandler getHibernateCustomFieldHandler() {
return hibernateCustomFieldHandler;
}
@Override
public List<Number[]> getNewMembersCountThroughTheTime(final Collection<? extends Group> groups, final Period period) {
final StringBuilder hql = new StringBuilder("select month(m.creationDate), year(m.creationDate), count(m.id) ");
hql.append(" from Member m ");
hql.append(" where 1=1 ");
final Map<String, Object> namedParameters = new HashMap<String, Object>();
if (groups != null && !groups.isEmpty()) {
HibernateHelper.addInParameterToQuery(hql, namedParameters, "m.group", groups);
}
if (period != null) {
HibernateHelper.addPeriodParameterToQuery(hql, namedParameters, "m.creationDate", period);
}
hql.append(" group by month(m.creationDate), year(m.creationDate) ");
hql.append(" order by year(m.creationDate), month(m.creationDate) ");
final List<Object[]> results = list(hql.toString(), namedParameters);
final Iterator<Object[]> i = results.iterator();
final List<Number[]> numberList = new ArrayList<Number[]>();
while (i.hasNext()) {
final Object[] row = i.next();
final Number[] intRow = new Integer[3];
intRow[0] = (Integer) row[0];
intRow[1] = (Integer) row[1];
intRow[2] = (Integer) row[2];
numberList.add(intRow);
}
return numberList;
}
/**
* gets the number of members which were in the specified group at any moment during the specified period. Used by Activity Stats: gross Product,
* number of transactions and % not trading for compare periods, Histogram, Single Period, and by Key Dev Stats number of members
*
* @param groups the set of groups in which the members must be counted.
* @param period the period in which they should be part of any of the groups
* @return an int indicating the number of members during that period in that set of groups
*
*/
@Override
public int getNumberOfMembersInGroupsInPeriod(final Collection<? extends Group> groups, final Period period) {
final StringBuilder hql = new StringBuilder(" select count(m.id) from Member m where 1=1 ");
final Map<String, Object> namedParameters = new HashMap<String, Object>();
if (CollectionUtils.isEmpty(groups) && period != null && period.getEnd() != null) {
namedParameters.put("endDate", period.getEnd());
hql.append(" and m.creationDate <= :endDate ");
} else if (!CollectionUtils.isEmpty(groups) && period != null && period.getEnd() != null && period.getBegin() != null) {
namedParameters.put("beginDate", period.getBegin());
namedParameters.put("endDate", period.getEnd());
namedParameters.put("groups", groups);
// First condition: it has been in one of the selected groups
hql.append(" and ( (m.group in (:groups) and m.creationDate < :endDate and not exists ");
hql.append(" (select gr1.id from GroupRemark gr1 where gr1.subject = m)) or ");
// Second: Changed the member's group inside the period.
hql.append(" (m.creationDate < :endDate and exists (select gr.id from GroupRemark gr where gr.subject=m and (gr.oldGroup in ");
hql.append(" (:groups) or gr.newGroup in (:groups)) and gr.date > :beginDate and gr.date <= :endDate)) or ");
// Third condition: the group remark right before the period put the member in one
// of the selected groups
hql.append(" exists (select gr2.id from GroupRemark gr2 where gr2.subject=m and ");
hql.append(" gr2.newGroup in (:groups) and gr2.date=(select max(gr3.date) from GroupRemark ");
hql.append(" gr3 where gr3.subject=m and gr3.date < :beginDate)) or ");
// Fourth condition: the group remark right after the begin period: the member was created
// then the group was changed in the period, we must use oldGroup.
hql.append(" (m.creationDate <= :endDate and exists (select gr2.id from GroupRemark gr2 where ");
hql.append(" gr2.subject=m and gr2.oldGroup in (:groups) and gr2.date = (select min(gr3.date) ");
hql.append(" from GroupRemark gr3 where gr3.subject=m and gr3.date > :endDate))) ");
hql.append(" ) ");
} else if (!CollectionUtils.isEmpty(groups)) {
hql.append(" and m.group in (:groups) ");
namedParameters.put("groups", groups);
}
final Number count = uniqueResult(hql.toString(), namedParameters);
return count.intValue();
}
@Override
public List<Number[]> getRemovedMembersCountThroughTheTime(final Collection<? extends Group> groups, final Period period) {
final Map<String, Object> namedParameters = new HashMap<String, Object>();
final StringBuilder hql = new StringBuilder("select month(gr.date), year(gr.date), count(gr.id) ");
hql.append(" from GroupRemark gr ");
hql.append(" where 1=1 ");
hql.append(" and exists ( ");
hql.append(" select gr.id ");
hql.append(" from GroupRemark gr ");
hql.append(" where ");
hql.append(" gr.subject = e ");
hql.append(" and gr.newGroup.status = :removed ");
namedParameters.put("removed", Group.Status.REMOVED);
// Deactivation period
if (period != null) {
HibernateHelper.addPeriodParameterToQuery(hql, namedParameters, "gr.date", period);
}
if (groups != null && !groups.isEmpty()) {
hql.append(" and gr.oldGroup in (:groups) ");
namedParameters.put("groups", groups);
} else {
return new ArrayList<Number[]>();
}
hql.append(" )");
hql.append(" and gr.newGroup.status = :removed ");
hql.append(" group by month(gr.date), year(gr.date) ");
hql.append(" order by year(gr.date), month(gr.date) ");
namedParameters.put("removed", Group.Status.REMOVED);
// Map<Integer, Integer> removedMembersCountThroughTheYears = new HashMap<Integer, Integer>();
final List<Object[]> results = list(hql.toString(), namedParameters);
final Iterator<Object[]> i = results.iterator();
final List<Number[]> numberList = new ArrayList<Number[]>();
while (i.hasNext()) {
final Object[] row = i.next();
final Number[] intRow = new Integer[3];
intRow[0] = (Integer) row[0];
intRow[1] = (Integer) row[1];
intRow[2] = (Integer) row[2];
numberList.add(intRow);
}
return numberList;
}
@Override
public boolean hasValueForField(final Member member, final MemberCustomField field) {
final Map<String, Object> namedParameters = new HashMap<String, Object>();
namedParameters.put("member", member);
namedParameters.put("field", field);
final StringBuilder hql = new StringBuilder();
hql.append(" select 1");
hql.append(" from MemberCustomFieldValue fv");
hql.append(" where fv.member = :member");
hql.append(" and fv.field = :field");
hql.append(" and (fv.possibleValue is not null or (fv.stringValue is not null and length(fv.stringValue) > 0))");
final List<?> list = list(ResultType.LIST, hql.toString(), namedParameters, PageParameters.max(1));
return !list.isEmpty();
}
@Override
public Iterator<Member> iterateMembers(final boolean ordered, final MemberGroup... groups) {
if (groups == null || groups.length == 0) {
return Collections.<Member> emptyList().iterator();
}
final Map<String, List<MemberGroup>> parameters = Collections.singletonMap("groups", Arrays.asList(groups));
return iterate("from Member m left join fetch m.user where m.group in (:groups) " + (ordered ? "order by m.name, m.user.username" : ""), parameters);
}
@Override
public List<Member> listMembersRegisteredBeforeOnGroup(final Calendar date, final MemberGroup group) {
final StringBuilder hql = new StringBuilder();
hql.append(" select m");
hql.append(" from GroupHistoryLog log, Member m left join fetch m.user ");
hql.append(" where log.element = m ");
hql.append(" and log.element.group = :group ");
hql.append(" and log.group = :group ");
hql.append(" and log.period.end is null ");
hql.append(" and log.period.begin < :date");
final Map<String, Object> namedParameters = new HashMap<String, Object>();
namedParameters.put("date", date);
namedParameters.put("group", group);
return list(ResultType.ITERATOR, hql.toString(), namedParameters, null, Element.Relationships.USER, Element.Relationships.GROUP);
}
@Override
public Member loadByCustomField(final MemberCustomField customField, final String value, final Relationship[] fetch) {
final Map<String, Object> namedParameters = new HashMap<String, Object>();
final StringBuilder hql = new StringBuilder();
hql.append(" select m");
hql.append(" from MemberCustomFieldValue fv inner join fv.member m inner join m.user u inner join fetch m.group g");
hql.append(" where g.status <> :removed");
hql.append(" and fv.field = :field");
hql.append(" and fv.stringValue = :value");
namedParameters.put("removed", Group.Status.REMOVED);
namedParameters.put("field", customField);
namedParameters.put("value", value);
final Member member = uniqueResult(hql.toString(), namedParameters);
if (member == null) {
throw new EntityNotFoundException(Member.class, null, String.format("Custom field used to load: <%1$s, %2$s>", customField.getInternalName(), value));
}
return member;
}
@Override
public Element loadByEmail(final String email, final Relationship... fetch) throws EntityNotFoundException {
final Map<String, Object> namedParameters = new HashMap<String, Object>();
final StringBuilder hql = HibernateHelper.getInitialQuery(Member.class, "m", Arrays.asList(fetch));
hql.append(" and m.group.status <> :removed");
hql.append(" and m.email = :email");
namedParameters.put("removed", Group.Status.REMOVED);
namedParameters.put("email", email);
final Element element = uniqueResult(hql.toString(), namedParameters);
if (element == null) {
throw new EntityNotFoundException(Element.class);
}
return element;
}
@Override
public void removeChannelsFromMembers(final MemberGroup group, final Collection<Channel> channels) {
if (CollectionUtils.isNotEmpty(channels)) {
final Map<String, Object> parameters = new HashMap<String, Object>();
final Set<Long> channelIds = new HashSet<Long>();
CollectionUtils.addAll(channelIds, EntityHelper.toIds(channels));
parameters.put("channelIds", channelIds);
parameters.put("groupId", group.getId());
final String statement = " delete from members_channels " +
" where channel_id in (:channelIds) " +
" and member_id in (select id from members where group_id = :groupId) ";
final SQLQuery query = getSession().createSQLQuery(statement);
getHibernateQueryHandler().setQueryParameters(query, parameters);
query.executeUpdate();
}
}
@Override
public List<Element> search(final ElementQuery query) {
Class<? extends Element> entityType;
if (query instanceof AdminQuery) {
entityType = Administrator.class;
} else if (query instanceof MemberQuery) {
entityType = Member.class;
} else if (query instanceof OperatorQuery) {
entityType = Operator.class;
} else {
throw new IllegalArgumentException("Invalid query parameters: " + query);
}
final Map<String, Object> namedParameters = new HashMap<String, Object>();
final Set<Relationship> fetch = query.getFetch();
final StringBuilder hql = new StringBuilder();
if (query instanceof MemberQuery && ((MemberQuery) query).isHasAds()) {
hql.append(" select distinct e");
hql.append(" from ").append(entityType.getName()).append(" e inner join e.ads ad ");
} else {
hql.append(" select e");
hql.append(" from ").append(entityType.getName()).append(" e ");
}
hibernateCustomFieldHandler.appendJoins(hql, "e.customValues", query.getCustomValues());
HibernateHelper.appendJoinFetch(hql, entityType, "e", fetch);
hql.append(" where 1=1 ");
if (query instanceof BrokerQuery) {
hql.append(" and exists (select 1 from " + BrokerGroup.class.getName() + " bg where bg = e.group) ");
}
if (query.getExcludeElements() != null && !query.getExcludeElements().isEmpty()) {
hql.append(" and e not in (:excludeElements) ");
namedParameters.put("excludeElements", query.getExcludeElements());
}
if (query.isExcludeRemoved()) {
hql.append(" and e.group.status <> :removedStatus");
namedParameters.put("removedStatus", Group.Status.REMOVED);
}
HibernateHelper.addRightLikeParameterToQuery(hql, namedParameters, "e.user.username", query.getUsername());
HibernateHelper.addLikeParameterToQuery(hql, namedParameters, "e.name", query.getName());
HibernateHelper.addRightLikeParameterToQuery(hql, namedParameters, "e.email", query.getEmail());
// Group filters are handled at service level
if (query.getGroups() != null && !query.getGroups().isEmpty()) {
HibernateHelper.addInParameterToQuery(hql, namedParameters, "e.group", query.getGroups());
}
HibernateHelper.addPeriodParameterToQuery(hql, namedParameters, "e.creationDate", query.getCreationPeriod());
final Boolean enabled = query.getEnabled();
// Specific tests for admins and members
if (query instanceof AdminQuery) {
if (enabled != null) {
// If searching for admins, enabled means normal groups, while disabled means removed admins
final Group.Status groupStatus = enabled ? Group.Status.NORMAL : Group.Status.REMOVED;
HibernateHelper.addParameterToQuery(hql, namedParameters, "e.group.status", groupStatus);
}
} else if (query instanceof MemberQuery) {
final MemberQuery memberQuery = (MemberQuery) query;
HibernateHelper.addPeriodParameterToQuery(hql, namedParameters, "e.activationDate", memberQuery.getActivationPeriod());
if (enabled != null) {
// For members enabled means the activationData must be not null / null for Enable / Disabled
hql.append(" and e.activationDate is " + (enabled ? "not" : "") + " null ");
if (enabled) {
// Enabled also has a normal group
HibernateHelper.addParameterToQuery(hql, namedParameters, "e.group.status", Group.Status.NORMAL);
}
}
// With images only
if (memberQuery.isWithImagesOnly()) {
hql.append(" and exists (select mi.id from MemberImage mi where mi.member=e)");
}
// Deactivation period
final Period deactivationPeriod = memberQuery.getDeactivationPeriod();
if (deactivationPeriod != null) {
hql.append(" and exists ( ");
hql.append(" select gr.id ");
hql.append(" from GroupRemark gr ");
hql.append(" where ");
hql.append(" gr.subject = e ");
hql.append(" and gr.newGroup.status = :removed ");
HibernateHelper.addPeriodParameterToQuery(hql, namedParameters, "gr.date", deactivationPeriod);
hql.append(" )");
namedParameters.put("removed", Group.Status.REMOVED);
}
// Has ads
final boolean hasAds = memberQuery.isHasAds();
if (hasAds) {
hql.append(" and ad.permanent=true or ( ");
hql.append(" ad.publicationPeriod.begin <= current_date() and ");
hql.append(" ad.publicationPeriod.end >= current_date() ");
hql.append(" ) ");
}
// Broker
if (memberQuery.getBroker() != null) {
HibernateHelper.addParameterToQuery(hql, namedParameters, "e.broker", memberQuery.getBroker());
}
// Group filters
if (CollectionUtils.isNotEmpty(memberQuery.getGroupFilters())) {
hql.append(" and exists (select gf.id from GroupFilter gf where gf in (:groupFilters) and e.group in elements(gf.groups))");
namedParameters.put("groupFilters", memberQuery.getGroupFilters());
}
} else if (query instanceof OperatorQuery) {
final OperatorQuery operatorQuery = (OperatorQuery) query;
hql.append(" and exists (");
hql.append(" select o.id from Operator o where o = e and o.member = :member");
hql.append(" )");
namedParameters.put("member", operatorQuery.getMember());
}
if (query.getViewableGroup() != null) {
hql.append(" and :mg in elements(e.group.canViewProfileOfGroups)");
namedParameters.put("mg", query.getViewableGroup());
}
hibernateCustomFieldHandler.appendConditions(hql, namedParameters, query.getCustomValues());
if (query.isRandomOrder()) {
HibernateHelper.appendOrder(hql, "rand()");
} else if (query.getOrder() != null) {
switch (query.getOrder()) {
case USERNAME:
HibernateHelper.appendOrder(hql, "e.user.username");
break;
case NAME:
HibernateHelper.appendOrder(hql, "e.name", "e.id");
break;
}
}
return list(query, hql.toString(), namedParameters);
}
@SuppressWarnings("unchecked")
public Iterator<Member> searchActiveMembers(final Collection<Group> toSearch) {
return getHibernateTemplate().iterate(" from " + Member.class.getName() + " m where m.group in (?) and exists (select 1 from " + Account.class.getName() + " a where a.member = m) ", toSearch);
}
@Override
public List<Element> searchAtDate(final MemberQuery query, final Calendar date) {
final StringBuilder hql = HibernateHelper.getInitialQuery(Member.class, "m", query.getFetch());
final Map<String, Object> namedParameters = new HashMap<String, Object>();
if (query.getBroker() != null) {
hql.append(" and m.broker = :broker ");
namedParameters.put("broker", query.getBroker());
}
if (date == null) {
hql.append(" and m.group in (:groups) ");
namedParameters.put("groups", query.getGroups());
} else {
if (!CollectionUtils.isEmpty(query.getGroups())) {
hql.append(" and ( m.creationDate <= :date ");
hql.append(" and (m.group in (:groups) and not exists ");
hql.append(" (select gr1.id from GroupRemark gr1 where gr1.subject=m)) ");
hql.append(" or exists (select gr2.id from GroupRemark gr2 where gr2.subject=m and ");
hql.append(" gr2.newGroup in (:groups) and gr2.date= ");
hql.append(" (select max(gr3.date) from GroupRemark gr3 ");
hql.append(" where gr3.subject=m and gr3.date <= :date)) ");
hql.append(" or (m.creationDate <= :date and exists (select gr2.id from ");
hql.append(" GroupRemark gr2 where gr2.subject=m and gr2.oldGroup in (:groups) ");
hql.append(" and gr2.date = (select min(gr3.date) from GroupRemark gr3 ");
hql.append(" where gr3.subject=m and gr3.date > :date)) ))");
namedParameters.put("groups", query.getGroups());
} else {
hql.append(" and m.creationDate <= :date ");
}
namedParameters.put("date", date);
}
return list(ResultType.ITERATOR, hql.toString(), namedParameters, query.getPageParameters());
}
// Used by Stats Key Dev > number new members
@Override
public List<Element> searchHistoryNew(final ElementQuery query) {
Class<? extends Element> entityType;
if (query instanceof AdminQuery) {
entityType = Administrator.class;
} else {
entityType = Member.class;
}
final Map<String, Object> namedParameters = new HashMap<String, Object>();
final Set<Relationship> fetch = query.getFetch();
final StringBuilder hql = new StringBuilder();
hql.append(" select e");
hql.append(" from ").append(entityType.getName()).append(" e ");
hibernateCustomFieldHandler.appendJoins(hql, "e.customValues", query.getCustomValues());
HibernateHelper.appendJoinFetch(hql, entityType, "e", fetch);
hql.append(" where 1=1");
HibernateHelper.addRightLikeParameterToQuery(hql, namedParameters, "e.user.username", query.getUsername());
HibernateHelper.addLikeParameterToQuery(hql, namedParameters, "e.name", query.getName());
final Collection<? extends Group> groups = query.getGroups();
final Boolean enabled = query.getEnabled();
// Specific tests for admins and members
if (query instanceof AdminQuery) {
HibernateHelper.addPeriodParameterToQuery(hql, namedParameters, "e.creationDate", query.getCreationPeriod());
if (groups != null && !groups.isEmpty()) {
HibernateHelper.addInParameterToQuery(hql, namedParameters, "e.group", groups);
}
if (enabled != null) {
// If searching for admins, enabled means normal groups, while disabled means removed admins
final Group.Status groupStatus = enabled ? Group.Status.NORMAL : Group.Status.REMOVED;
HibernateHelper.addParameterToQuery(hql, namedParameters, "e.group.status", groupStatus);
}
} else {
if (groups != null && !groups.isEmpty()) {
hql.append(" and ( ( 1 = 1");
final Period creationPeriod = query.getCreationPeriod();
if (creationPeriod != null) {
HibernateHelper.addPeriodParameterToQuery(hql, namedParameters, "e.creationDate", creationPeriod);
}
hql.append(" and ((not exists ");
hql.append(" (select gr.id from GroupRemark gr where gr.subject = e) ");
hql.append(" and e.group in (:groups) )");
namedParameters.put("groups", groups);
hql.append(" or exists ( ");
hql.append(" select gr.id ");
hql.append(" from GroupRemark gr ");
hql.append(" where ");
hql.append(" gr.subject = e ");
if (groups != null && !groups.isEmpty()) {
hql.append(" and gr.oldGroup in (:groups) ) ");
}
hql.append(")) or ");
hql.append(" exists ( ");
hql.append(" select gr.id ");
hql.append(" from GroupRemark gr ");
hql.append(" where ");
hql.append(" gr.subject = e ");
// using 'creation period'
if (creationPeriod != null) {
HibernateHelper.addPeriodParameterToQuery(hql, namedParameters, "gr.date", creationPeriod);
}
if (groups != null && !groups.isEmpty()) {
// hql.append(" and (gr.newGroup in (:groups) ");
hql.append(" and gr.newGroup in (:groups) and gr.oldGroup not in (:groups) ");
namedParameters.put("groups", groups);
}
hql.append(" )");
hql.append(" ) ");
} else {
final Period creationPeriod = query.getCreationPeriod();
if (creationPeriod != null) {
HibernateHelper.addPeriodParameterToQuery(hql, namedParameters, "e.creationDate", creationPeriod);
}
}
}
// Custom Values
hibernateCustomFieldHandler.appendConditions(hql, namedParameters, query.getCustomValues());
HibernateHelper.appendOrder(hql, "e.user.username");
return list(query, hql.toString(), namedParameters);
}
// Used by Stats Key Developments > number of (disappeared) members
@Override
public List<Element> searchHistoryRemoved(final ElementQuery query) {
Class<? extends Element> entityType;
if (query instanceof AdminQuery) {
entityType = Administrator.class;
} else {
entityType = Member.class;
}
final Map<String, Object> namedParameters = new HashMap<String, Object>();
final Set<Relationship> fetch = query.getFetch();
final StringBuilder hql = new StringBuilder();
hql.append(" select e");
hql.append(" from ").append(entityType.getName()).append(" e ");
hibernateCustomFieldHandler.appendJoins(hql, "e.customValues", query.getCustomValues());
HibernateHelper.appendJoinFetch(hql, entityType, "e", fetch);
hql.append(" where 1=1");
if (query instanceof BrokerQuery) {
hql.append(" and exists (select 1 from " + BrokerGroup.class.getName() + " bg where bg = e.group) ");
}
HibernateHelper.addRightLikeParameterToQuery(hql, namedParameters, "e.user.username", query.getUsername());
HibernateHelper.addLikeParameterToQuery(hql, namedParameters, "e.name", query.getName());
final MemberQuery memberQuery = (MemberQuery) query;
final Boolean enabled = query.getEnabled();
// Specific tests for admins and members
if (query instanceof AdminQuery) {
if (enabled != null) {
// If searching for admins, enabled means normal groups, while disabled means removed admins
final Group.Status groupStatus = enabled ? Group.Status.NORMAL : Group.Status.REMOVED;
HibernateHelper.addParameterToQuery(hql, namedParameters, "e.group.status", groupStatus);
}
} else {
hql.append(" and exists ( ");
hql.append(" select gr.id ");
hql.append(" from GroupRemark gr ");
hql.append(" where ");
hql.append(" gr.subject = e ");
// Deactivation period
final Period deactivationPeriod = memberQuery.getDeactivationPeriod();
if (deactivationPeriod != null) {
HibernateHelper.addPeriodParameterToQuery(hql, namedParameters, "gr.date", deactivationPeriod);
}
// if at least one group was chosen.
// if more than one group is selected, it should not count moving
// the members from and to those groups, because they are the 'same group' in this case.
final Collection<? extends Group> groups = query.getGroups();
if (groups != null && !groups.isEmpty()) {
hql.append(" and gr.oldGroup in (:groups) and gr.newGroup not in (:groups) ");
namedParameters.put("groups", groups);
}
// no group was chosen, no disappears members is returned;
else {
return new ArrayList<Element>();
}
hql.append(" )");
}
// Custom Values
hibernateCustomFieldHandler.appendConditions(hql, namedParameters, query.getCustomValues());
HibernateHelper.appendOrder(hql, "e.user.username");
return list(query, hql.toString(), namedParameters);
}
public void setHibernateCustomFieldHandler(final HibernateCustomFieldHandler hibernateCustomFieldHandler) {
this.hibernateCustomFieldHandler = hibernateCustomFieldHandler;
}
public void setSettingsServiceLocal(final SettingsServiceLocal settingsService) {
this.settingsService = settingsService;
}
private Sort decideSorting(final FullTextElementQuery elementQuery) {
Sort sort;
// sorting
LocalSettings localSettings = settingsService.getLocalSettings();
SortOrder memberSortOrder = localSettings.getMemberSortOrder();
if (elementQuery instanceof FullTextMemberQuery) {
FullTextMemberQuery memberQuery = (FullTextMemberQuery) elementQuery;
if (memberQuery.getMemberSortOrder() != null) {
memberSortOrder = memberQuery.getMemberSortOrder();
}
}
if (memberSortOrder == SortOrder.CHRONOLOGICAL) {
sort = new Sort(new SortField("creationDate", SortField.STRING, true));
} else {
if (elementQuery.getNameDisplay() == MemberResultDisplay.NAME) {
sort = new Sort(new SortField("nameForSort", SortField.STRING));
} else {
sort = new Sort(new SortField("usernameForSort", SortField.STRING));
}
}
return sort;
}
private MultiFieldQueryParser getQueryParser(final Analyzer analyzer) {
final Map<String, Float> boosts = new HashMap<String, Float>();
boosts.put("name", 2.0F);
boosts.put("username", 1.5F);
return new MultiFieldQueryParser(LuceneUtils.LUCENE_VERSION, FIELDS_FULL_TEXT, analyzer, boosts);
}
}