001/* 002 * Copyright 2010 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.newsletter.daos; 017 018import java.util.Collection; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022import java.util.Optional; 023 024import org.apache.avalon.framework.thread.ThreadSafe; 025import org.apache.ibatis.session.RowBounds; 026import org.apache.ibatis.session.SqlSession; 027 028import org.ametys.core.datasource.AbstractMyBatisDAO; 029import org.ametys.core.trace.ForensicLogger; 030 031/** 032 * DAO for accessing newsletters subscribers. 033 */ 034public class SubscribersDAO extends AbstractMyBatisDAO implements ThreadSafe 035{ 036 /** The Avalon role name. */ 037 public static final String ROLE = SubscribersDAO.class.getName(); 038 039 private static final Map<String, String> __ORDER_TO_COL_MAPPING = Map.of( 040 "email", "Email", 041 "siteName", "Site_Name", 042 "categoryId", "Category", 043 "subscribedAt", "Subscribed_At", 044 "token", "Token" 045 ); 046 047 /** 048 * Origin of the unsubscription 049 */ 050 public enum UnsubscribeOrigin 051 { 052 /** the subscriber to action to unsubscribe */ 053 SUBSCRIBER, 054 /** an administrator of the newsletter unsubscribed the subscriber */ 055 ADMINISTRATOR, 056 /** a data policy removed the subscription */ 057 DATAPOLICY, 058 } 059 060 private List<Subscriber> _getSubscribers(Map<String, Object> params) 061 { 062 return _getSubscribers(params, null); 063 } 064 065 private List<Subscriber> _getSubscribers(Map<String, Object> params, List<Map<String, Object>> sorts) 066 { 067 return _getSubscribers(params, sorts, RowBounds.DEFAULT); 068 } 069 070 private List<Subscriber> _getSubscribers(Map<String, Object> params, List<Map<String, Object>> sorts, RowBounds rowBounds) 071 { 072 Map<String, Object> queryParams = new HashMap<>(params); 073 074 if (sorts != null) 075 { 076 StringBuilder sortString = new StringBuilder(); 077 078 for (Map<String, Object> sort : sorts) 079 { 080 String property = (String) sort.get("property"); 081 sortString.append(__ORDER_TO_COL_MAPPING.getOrDefault(property, property)); 082 sortString.append(" "); 083 sortString.append(Optional.of("direction").map(sort::get).orElse("ASC")); 084 sortString.append(","); 085 } 086 087 if (!sorts.isEmpty()) 088 { 089 sortString.deleteCharAt(sortString.length() - 1); 090 queryParams.put("__order", sortString.toString()); 091 } 092 } 093 094 try (SqlSession session = getSession()) 095 { 096 return session.selectList("Subscribers.getSubscribers", queryParams, rowBounds); 097 } 098 } 099 100 /** 101 * Get the whole list for subscribers 102 * @return The list for subscribers 103 */ 104 public List<Subscriber> getSubscribers() 105 { 106 return _getSubscribers(Map.of()); 107 } 108 109 /** 110 * Get the whole list for subscribers 111 * @param sorts The sorts list 112 * @return The list for subscribers 113 */ 114 public List<Subscriber> getSubscribers(List<Map<String, Object>> sorts) 115 { 116 return _getSubscribers(Map.of(), sorts); 117 } 118 119 /** 120 * Get the subscribers to a newsletter category 121 * @param siteName The site name 122 * @param categoryId The newsletter category's id 123 * @return the subscribers 124 */ 125 public List<Subscriber> getSubscribers (String siteName, String categoryId) 126 { 127 return _getSubscribers( 128 Map.of( 129 "siteName", siteName, 130 "category", categoryId 131 ) 132 ); 133 } 134 135 /** 136 * Get the subscribers to a newsletter category 137 * @param siteName The site name 138 * @param categoryId The newsletter category's id 139 * @param sorts The sorts list 140 * @param offset The number of results to ignore. 141 * @param limit The maximum number of results to return. 142 * @return the subscribers 143 */ 144 public List<Subscriber> getSubscribers (String siteName, String categoryId, List<Map<String, Object>> sorts, int offset, int limit) 145 { 146 return _getSubscribers( 147 Map.of( 148 "siteName", siteName, 149 "category", categoryId 150 ), 151 sorts, 152 new RowBounds(offset, limit) 153 ); 154 } 155 156 /** 157 * Get the subscribers count for a newsletter category 158 * @param siteName The site name 159 * @param categoryId The newsletter category's id 160 * @return the subscribers count 161 */ 162 public int getSubscribersCount (String siteName, String categoryId) 163 { 164 Map<String, Object> params = new HashMap<>(); 165 params.put("siteName", siteName); 166 params.put("category", categoryId); 167 168 try (SqlSession session = getSession()) 169 { 170 return (Integer) session.selectOne("Subscribers.getSubscribersCount", params); 171 } 172 } 173 174 /** 175 * Get a subscriber to a newsletter category 176 * @param email The subscriber email 177 * @param siteName The site name 178 * @param categoryId The newsletter category's id 179 * @return the subscribers 180 */ 181 public Subscriber getSubscriber (String email, String siteName, String categoryId) 182 { 183 return _getSubscribers( 184 Map.of( 185 "email", email, 186 "siteName", siteName, 187 "category", categoryId 188 ) 189 ) 190 .stream() 191 .findFirst() 192 .orElse(null); 193 } 194 195 /** 196 * Get a subscriber by his token 197 * @param token The user token 198 * @return the subscribers 199 */ 200 public Subscriber getSubscriberByToken (String token) 201 { 202 return _getSubscribers(Map.of("token", token)) 203 .stream() 204 .findFirst() 205 .orElse(null); 206 } 207 208 /** 209 * Get the list of subscriptions for a given email and site name. 210 * @param email the email. 211 * @param siteName the site name. 212 * @return the list of subscriptions. 213 */ 214 public List<Subscriber> getSubscriptions(String email, String siteName) 215 { 216 return _getSubscribers( 217 Map.of( 218 "email", email, 219 "siteName", siteName 220 ) 221 ); 222 } 223 224 /** 225 * Subscribes to the newsletter 226 * @param subscriber The subscriber 227 */ 228 public void subscribe (Subscriber subscriber) 229 { 230 try (SqlSession session = getSession(true)) 231 { 232 session.insert("Subscribers.subscribe", subscriber); 233 } 234 } 235 236 /** 237 * Insert several subscriptions to newsletters. 238 * @param subscribers a list of subscribers. 239 */ 240 public void subscribe(Collection<Subscriber> subscribers) 241 { 242 try (SqlSession session = getSession()) 243 { 244 for (Subscriber subscriber : subscribers) 245 { 246 session.insert("Subscribers.subscribe", subscriber); 247 } 248 249 session.commit(); 250 } 251 } 252 253 254 /** 255 * Insert several subscriptions to newsletters. 256 * @param newSubscribers the collection of subscribers to insert. 257 * @param removeSubscriptions the collection of subscription tokens to remove. 258 * @param origin the origin of the unsubscription 259 */ 260 public void modifySubscriptions(Collection<Subscriber> newSubscribers, Collection<String> removeSubscriptions, UnsubscribeOrigin origin) 261 { 262 try (SqlSession session = getSession()) 263 { 264 for (Subscriber subscriber : newSubscribers) 265 { 266 session.insert("Subscribers.subscribe", subscriber); 267 } 268 269 for (String tokenToRemove : removeSubscriptions) 270 { 271 Subscriber subscriber = getSubscriberByToken(tokenToRemove); 272 if (subscriber != null) 273 { 274 session.update("Subscribers.unsubscribe", tokenToRemove); 275 ForensicLogger.info("newsletter.unsubscribe", Map.of("email", subscriber.getEmail(), "siteName", subscriber.getSiteName(), "category", subscriber.getCategoryId(), "origin", origin.name()), null); 276 } 277 } 278 279 session.commit(); 280 } 281 } 282 283 /** 284 * Unsubscribes to the newsletter 285 * @param token The unique token 286 * @param origin the origin of the unsubscription 287 */ 288 public void unsubscribe (String token, UnsubscribeOrigin origin) 289 { 290 try (SqlSession session = getSession(true)) 291 { 292 Subscriber subscriber = getSubscriberByToken(token); 293 if (subscriber != null) 294 { 295 session.update("Subscribers.unsubscribe", token); 296 ForensicLogger.info("newsletter.unsubscribe", Map.of("email", subscriber.getEmail(), "siteName", subscriber.getSiteName(), "category", subscriber.getCategoryId(), "origin", origin.name()), null); 297 } 298 } 299 } 300 301 /** 302 * Empty a category's subscribers. 303 * @param categoryId the category to empty. 304 * @param siteName the site name. 305 */ 306 public void empty(String categoryId, String siteName) 307 { 308 Map<String, Object> params = new HashMap<>(); 309 params.put("categoryId", categoryId); 310 params.put("siteName", siteName); 311 312 try (SqlSession session = getSession(true)) 313 { 314 session.delete("Subscribers.empty", params); 315 } 316 } 317 318 /** 319 * Remove all subscriptions for a subscriber in a given site. 320 * @param email the category to empty. 321 * @param siteName the site name. 322 * @param origin the origin of the unsubscription 323 * @return the number of subscription removed 324 */ 325 public int unsubscribe(String email, String siteName, UnsubscribeOrigin origin) 326 { 327 Map<String, Object> params = new HashMap<>(); 328 params.put("email", email); 329 params.put("siteName", siteName); 330 331 try (SqlSession session = getSession(true)) 332 { 333 int result = session.delete("Subscribers.removeSubscriptionsByEmail", params); 334 if (result > 0) 335 { 336 ForensicLogger.info("newsletter.unsubscribe", Map.of("email", email, "siteName", siteName, "origin", origin.name()), null); 337 } 338 return result; 339 } 340 } 341}