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;
029
030/**
031 * DAO for accessing newsletters subscribers.
032 */
033public class SubscribersDAO extends AbstractMyBatisDAO implements ThreadSafe
034{
035    /** The Avalon role name. */
036    public static final String ROLE = SubscribersDAO.class.getName();
037    
038    private static final Map<String, String> __ORDER_TO_COL_MAPPING = Map.of(
039        "email", "Email",
040        "siteName", "Site_Name",
041        "categoryId", "Category",
042        "subscribedAt", "Subscribed_At",
043        "token", "Token"
044    );
045
046    private List<Subscriber> _getSubscribers(Map<String, Object> params)
047    {
048        return _getSubscribers(params, null);
049    }
050    
051    private List<Subscriber> _getSubscribers(Map<String, Object> params, List<Map<String, Object>> sorts)
052    {
053        return _getSubscribers(params, sorts, RowBounds.DEFAULT);
054    }
055    
056    private List<Subscriber> _getSubscribers(Map<String, Object> params, List<Map<String, Object>> sorts, RowBounds rowBounds)
057    {
058        Map<String, Object> queryParams = new HashMap<>(params);
059        
060        if (sorts != null)
061        {
062            StringBuilder sortString = new StringBuilder();
063            
064            for (Map<String, Object> sort : sorts)
065            {
066                String property = (String) sort.get("property");
067                sortString.append(__ORDER_TO_COL_MAPPING.getOrDefault(property, property));
068                sortString.append(" ");
069                sortString.append(Optional.of("direction").map(sort::get).orElse("ASC"));
070                sortString.append(",");
071            }
072            
073            if (!sorts.isEmpty())
074            {
075                sortString.deleteCharAt(sortString.length() - 1);
076                queryParams.put("__order", sortString.toString());
077            }
078        }
079        
080        try (SqlSession session = getSession())
081        {
082            return session.selectList("Subscribers.getSubscribers", queryParams, rowBounds);
083        }
084    }
085
086    /**
087     * Get the whole list for subscribers
088     * @return The list for subscribers
089     */
090    public List<Subscriber> getSubscribers()
091    {
092        return _getSubscribers(Map.of());
093    }
094    
095    /**
096     * Get the whole list for subscribers
097     * @param sorts The sorts list
098     * @return The list for subscribers
099     */
100    public List<Subscriber> getSubscribers(List<Map<String, Object>> sorts)
101    {
102        return _getSubscribers(Map.of(), sorts);
103    }
104    
105    /**
106     * Get the subscribers to a newsletter category
107     * @param siteName The site name
108     * @param categoryId The newsletter category's id
109     * @return the subscribers
110     */
111    public List<Subscriber> getSubscribers (String siteName, String categoryId)
112    {
113        return _getSubscribers(
114                Map.of(
115                    "siteName", siteName,
116                    "category", categoryId
117                )
118            );
119    }
120    
121    /**
122     * Get the subscribers to a newsletter category
123     * @param siteName The site name
124     * @param categoryId The newsletter category's id
125     * @param sorts The sorts list
126     * @param offset The number of results to ignore.
127     * @param limit The maximum number of results to return.
128     * @return the subscribers
129     */
130    public List<Subscriber> getSubscribers (String siteName, String categoryId, List<Map<String, Object>> sorts, int offset, int limit)
131    {
132        return _getSubscribers(
133                Map.of(
134                    "siteName", siteName,
135                    "category", categoryId
136                ),
137                sorts,
138                new RowBounds(offset, limit)
139            );
140    }
141    
142    /**
143     * Get the subscribers count for a newsletter category
144     * @param siteName The site name
145     * @param categoryId The newsletter category's id
146     * @return the subscribers count
147     */
148    public int getSubscribersCount (String siteName, String categoryId)
149    {
150        Map<String, Object> params = new HashMap<>();
151        params.put("siteName", siteName);
152        params.put("category", categoryId);
153        
154        try (SqlSession session = getSession())
155        {
156            return (Integer) session.selectOne("Subscribers.getSubscribersCount", params);
157        }
158    }
159    
160    /**
161     * Get a subscriber to a newsletter category
162     * @param email The subscriber email
163     * @param siteName The site name
164     * @param categoryId The newsletter category's id
165     * @return the subscribers
166     */
167    public Subscriber getSubscriber (String email, String siteName, String categoryId)
168    {
169        return _getSubscribers(
170                Map.of(
171                    "email", email,
172                    "siteName", siteName,
173                    "category", categoryId
174                )
175            )
176            .stream()
177            .findFirst()
178            .orElse(null);
179    }
180    
181    /**
182     * Get a subscriber by his token
183     * @param token The user token
184     * @return the subscribers
185     */
186    public Subscriber getSubscriberByToken (String token)
187    {
188        return _getSubscribers(Map.of("token", token))
189            .stream()
190            .findFirst()
191            .orElse(null);
192    }
193    
194    /**
195     * Get the list of subscriptions for a given email and site name.
196     * @param email the email.
197     * @param siteName the site name.
198     * @return the list of subscriptions.
199     */
200    public List<Subscriber> getSubscriptions(String email, String siteName)
201    {
202        return _getSubscribers(
203                Map.of(
204                    "email", email,
205                    "siteName", siteName
206                )
207            );
208    }
209    
210    /**
211     * Subscribes to the newsletter
212     * @param subscriber The subscriber
213     */
214    public void subscribe (Subscriber subscriber)
215    {
216        try (SqlSession session = getSession(true))
217        {
218            session.insert("Subscribers.subscribe", subscriber);
219        }
220    }
221    
222    /**
223     * Insert several subscriptions to newsletters.
224     * @param subscribers a list of subscribers.
225     */
226    public void subscribe(Collection<Subscriber> subscribers)
227    {
228        try (SqlSession session = getSession())
229        {
230            for (Subscriber subscriber : subscribers)
231            {
232                session.insert("Subscribers.subscribe", subscriber);
233            }
234            
235            session.commit();
236        }
237    }
238    
239    
240    /**
241     * Insert several subscriptions to newsletters.
242     * @param newSubscribers the collection of subscribers to insert.
243     * @param removeSubscriptions the collection of subscription tokens to remove.
244     */
245    public void modifySubscriptions(Collection<Subscriber> newSubscribers, Collection<String> removeSubscriptions)
246    {
247        try (SqlSession session = getSession())
248        {
249            for (Subscriber subscriber : newSubscribers)
250            {
251                session.insert("Subscribers.subscribe", subscriber);
252            }
253            
254            for (String tokenToRemove : removeSubscriptions)
255            {
256                session.update("Subscribers.unsubscribe", tokenToRemove);
257            }
258            
259            session.commit();
260        }
261    }
262    
263    /**
264     * Unsubscribes to the newsletter
265     * @param token The unique token
266     */
267    public void unsubscribe (String token)
268    {
269        try (SqlSession session = getSession(true))
270        {
271            session.update("Subscribers.unsubscribe", token);
272        }
273    }
274    
275    /**
276     * Empty a category's subscribers.
277     * @param categoryId the category to empty.
278     * @param siteName the site name.
279     */
280    public void empty(String categoryId, String siteName)
281    {
282        Map<String, Object> params = new HashMap<>();
283        params.put("categoryId", categoryId);
284        params.put("siteName", siteName);
285        
286        try (SqlSession session = getSession(true))
287        {
288            session.delete("Subscribers.empty", params);
289        }
290    }
291    
292    /**
293     * Remove all subscriptions for a subscriber in a given site.
294     * @param email the category to empty.
295     * @param siteName the site name.
296     */
297    public void unsubscribe(String email, String siteName)
298    {
299        Map<String, Object> params = new HashMap<>();
300        params.put("email", email);
301        params.put("siteName", siteName);
302        
303        try (SqlSession session = getSession(true))
304        {
305            session.delete("Subscribers.removeSubscriptionsByEmail", params);
306        }
307    }
308}