001/*
002 *  Copyright 2015 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.sms.dao;
017
018import java.util.ArrayList;
019import java.util.Date;
020import java.util.HashMap;
021import java.util.LinkedList;
022import java.util.List;
023import java.util.Map;
024
025import org.apache.commons.lang3.StringUtils;
026import org.apache.ibatis.session.ResultContext;
027import org.apache.ibatis.session.ResultHandler;
028import org.apache.ibatis.session.RowBounds;
029import org.apache.ibatis.session.SqlSession;
030
031import org.ametys.core.datasource.AbstractMyBatisDAO;
032import org.ametys.core.ui.Callable;
033import org.ametys.plugins.sms.SMSHelper;
034
035/**
036 * DAO for manipulating SMS subscribers.
037 *
038 */
039public class SubscriberDAO extends AbstractMyBatisDAO
040{
041    /** The Avalon role */
042    public static final String ROLE = SubscriberDAO.class.getName();
043    
044    /**
045     * Get all the phone numbers in the database form the list
046     * @param list the id of the phone number list
047     * @return A map, where keys are phone number and value are date object.
048     */
049    public Map<String, Date> getPhoneNumbersFromList(String list)
050    {
051        Map<String, Object> params = new HashMap<>();
052        params.put("list", list);
053        
054        Map<String, Date> phoneNumbers = new HashMap<>();
055        try (SqlSession session = getSession())
056        {
057            List<Map<String, Object>> results = session.selectList("SmsSubscribers.getPhoneNumbers", params);
058            for (Map<String, Object> result : results)
059            {
060                phoneNumbers.put((String) result.get("PhoneNumber"), (Date) result.get("Date"));
061            }
062        }
063        
064        return phoneNumbers;
065    }
066    
067    /**
068     * Insert the phoneNumber in the database
069     * @param phoneNumber the phone number 
070     * @param list the id of the phone number list
071     */
072    public void insertNumber(String phoneNumber, String list)
073    {
074        try (SqlSession sqlSession = getSession())
075        {
076            String stmtId = "SmsSubscribers.insertNumber";
077            
078            Map<String, Object> params = new HashMap<>();
079            params.put("phoneNumber", phoneNumber);
080            params.put("list", list);
081            params.put("date", new Date());
082            
083            // Insert the session object and get the generated ID.
084            sqlSession.insert(stmtId, params);
085            
086            // Commit the transaction.
087            sqlSession.commit();
088        }
089    }
090    
091    /**
092     * Check if the phoneNumber exists in the database
093     * @param phoneNumber the phone number
094     * @param list the id of the list
095     * @return true if exist
096     */
097    public boolean numberAlreadyExists(String phoneNumber, String list)
098    {
099        String stmtId = "SmsSubscribers.getPhoneNumbers";
100        
101        try (SqlSession session = getSession())
102        {
103            Map<String, Object> params = new HashMap<>();
104            params.put("phoneNumber", phoneNumber);
105            params.put("list", list);
106            
107            List<Map> selectList = session.selectList(stmtId, params, new RowBounds(RowBounds.NO_ROW_OFFSET, 1));
108            return selectList.size() > 0;
109        }
110    }
111    
112    /**
113     * Creates a SMS subscriber.
114     * @param listId The id of the SMS list to subscribe to.
115     * @param phoneNumber The phone number to add
116     * @return The list id and the phone number of the added subscriber, or an error
117     */
118    @Callable
119    public Map<String, String> createSubscriber(String listId, String phoneNumber)
120    {
121        Map<String, String> result = new HashMap<>();
122        
123        try
124        {
125            String realPhoneNumber = phoneNumber.trim();
126            realPhoneNumber = SMSHelper.transformPhoneNumber(realPhoneNumber);
127            if (!SMSHelper.checkPhoneNumber(realPhoneNumber) || !SMSHelper.PHONE_NUMBER_INTERNATIONAL_VALIDATOR.matcher(realPhoneNumber).matches())
128            {   
129                result.put("error", "wrong-format");
130            }
131            else if (numberAlreadyExists(realPhoneNumber, listId))
132            {
133                result.put("error", "already-exists");
134            }
135            else
136            {
137                insertNumber(realPhoneNumber, listId);
138                result.put("phoneNumber", realPhoneNumber);
139                result.put("smsListId", listId);
140            }
141        }
142        catch (Exception e)
143        {
144            getLogger().error("Unable to add a new subscriber", e);
145            result.put("error", "exception");
146        }
147        
148        return result;
149    }
150    
151    /**
152     * Delete the phoneNumber in the database
153     * @param phoneNumber the phone number 
154     * @param list the id of the phone number list
155     */
156    public void deleteNumber(String phoneNumber, String list)
157    {
158        try (SqlSession sqlSession = getSession())
159        {
160            String stmtId = "SmsSubscribers.deleteNumber";
161            
162            Map<String, Object> params = new HashMap<>();
163            if (StringUtils.isNotEmpty(phoneNumber))
164            {
165                params.put("phoneNumber", phoneNumber);
166            }
167            if (StringUtils.isNotEmpty(list))
168            {
169                params.put("list", list);
170            }
171            
172            // Insert the session object and get the generated ID.
173            sqlSession.delete(stmtId, params);
174            
175            // Commit the transaction.
176            sqlSession.commit();
177        }
178    }
179    
180    /**
181     * Delete every phone number of a list
182     * @param list the id of the phone number list
183     */
184    public void deleteAllNumbers(String list)
185    {
186        deleteNumber(null, list);
187    }
188    
189    /**
190     * Deletes the given subscribers.
191     * @param listId The The id of the SMS list.
192     * @param phoneNumbers The phone numbers to delete
193     * @return The list id, the numbers deleted, the numbers not deleted and/or an error.
194     */
195    @Callable
196    public Map<String, Object> deleteSubscribers(String listId, ArrayList<String> phoneNumbers)
197    {
198        Map<String, Object> result = new HashMap<>();
199        List<String> numbersDeleted = new LinkedList<>();
200        List<String> numbersNotDeleted = new LinkedList<>();
201        
202        for (String phoneNumber : phoneNumbers)
203        {
204            try
205            {
206                deleteNumber(phoneNumber, listId);
207                numbersDeleted.add(phoneNumber);
208            }
209            catch (Exception e)
210            {
211                getLogger().error("Unable to delete the subscriber " + phoneNumber, e);
212                numbersNotDeleted.add(phoneNumber);
213                result.put("error", "exception");
214            }
215        }
216        
217        result.put("listId", listId);
218        result.put("numbersDeleted", numbersDeleted);
219        result.put("numbersNotDeleted", numbersNotDeleted);
220        
221        return result;
222    }
223    
224    /**
225     * Get the number of user in a list
226     * @return the number of user for each sms list
227     */
228    public Map<String, Number> getNbUserFromList()
229    {
230        Map<String, Number> userCounts = new HashMap<>();
231        try (SqlSession session = getSession())
232        {
233            session.select("SmsSubscribers.getUserCounts", new ResultHandler<Map<String, Object>>()
234            {
235                @Override
236                public void handleResult(ResultContext<? extends Map<String, Object>> context)
237                {
238                    final Map<String, Object> map = context.getResultObject();
239                    userCounts.put((String) map.get("ListId"), (Number) map.get("nb"));
240                }
241            });
242        }
243        
244        return userCounts;
245    }
246}