Wittyshare  0.2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
WsNewsLetter.cpp
Go to the documentation of this file.
1 /*
2 * Copyright (C) 2006-Today Guy Deleeuw
3 *
4 * See the LICENSE file for terms of use.
5 */
6 
7 #include <stdio.h>
8 
9 #include <iostream>
10 
11 #include <boost/filesystem.hpp>
12 
13 //#include <vmime/vmime.hpp>
14 //#include <vmime/platforms/posix/posixHandler.hpp>
15 
16 #include <Wt/WLogger>
17 #include <Wt/WText>
18 #include <Wt/WAnchor>
19 #include <Wt/WRegExpValidator>
20 #include <Wt/WValidator>
21 #include <Wt/WDate>
22 #include <Wt/WTime>
23 #include <Wt/WRandom>
24 #include <Wt/Dbo/WtSqlTraits>
25 
26 #include <Wt/Dbo/Dbo>
27 #include <Wt/Dbo/Session>
28 #include <Wt/Dbo/backend/Sqlite3>
29 
30 #include <Wt/Auth/HashFunction>
31 #include <Wt/Mail/Client>
32 #include <Wt/Mail/Message>
33 
34 #include <gdcore/gdCore.h>
35 #include <gdcore/gdLdap.h>
36 
37 #include <Logger/WsLogger.h>
39 
40 #include <Main/WsApplication.h>
41 
42 #include "EmailToken.h"
43 #include "WsNewsLetter.h"
44 
45 // Class WsNewsLetter
46 // ==================
47 WsNewsLetter::WsNewsLetter(WContainerWidget* parent)
48  : WContainerWidget(parent), m_pLineEdit(0), m_pButSubscribe(0), sqlite3_(0)
49 {
50  addStyleClass("WsNewsLetter");
51 }
52 
54 {
55  if ( sqlite3_ )
56  delete sqlite3_;
57  sqlite3_ = 0;
58 }
59 
61 {
62  WContainerWidget::load();
63  initDB();
64  WText* pTitle = new WText(asString(option("title")).toUTF8());
65  pTitle->addStyleClass("WsTitle");
66  addWidget(pTitle);
67  WText* pSubTitle = new WText(asString(option("subTitle")).toUTF8());
68  pSubTitle->addStyleClass("WsSubTitle");
69  addWidget(pSubTitle);
70  WRegExpValidator* validator = new WRegExpValidator("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}");
71  m_pLineEdit = new WLineEdit();
72  m_pLineEdit->addStyleClass("WsEmailAdr");
73  m_pLineEdit->setValidator(validator);
74  m_pLineEdit->keyWentUp().connect(SLOT(this, WsNewsLetter::doLineEditChanged));
75  m_pLineEdit->enterPressed().connect(SLOT(this, WsNewsLetter::doSubscribe));
76  addWidget(m_pLineEdit);
77  WPushButton* m_pButSubscribe = new WPushButton("Subscribe");
78  m_pButSubscribe->addStyleClass("WsBtnSubscribe");
79  m_pButSubscribe->clicked().connect(SLOT(this, WsNewsLetter::doSubscribe));
80  addWidget(m_pButSubscribe);
81  if ( asString(option("useReadAll")) == "true" ) {
82  std::string link = asString(option("link")).toUTF8();
83  std::string text = asString(option("text")).toUTF8();
84  WAnchor* pAnchor = new WAnchor(WLink(WLink::InternalPath, link), text);
85  pAnchor->addStyleClass("WsReadAll");
86  addWidget(pAnchor);
87  }
88 }
89 
91 {
92  //Init DB
93  // Implemantation from EMWEB
94  std::string dbPath = asString(option("dbNewsLetter")).toUTF8();
95  sqlite3_ = new dbo::backend::Sqlite3(dbPath);
96  sqlite3_->setProperty("show-queries", "true");
97  session_.setConnection(*sqlite3_);
98  session_.mapClass<EmailToken>("user");
99  try {
100  session_.createTables(); //Use it to create the DB.
101  } catch (std::exception& e) {
102  wApp->log("notice") << "WsNewsLetter::initDB() sqlite3 createTables and database : using existing database error = " << e.what();
103  }
104 }
105 
107 {
108  if ( m_pButSubscribe && m_pLineEdit )
109  m_pButSubscribe->setDisabled(m_pLineEdit->validate() != Wt::WValidator::Valid);
110 }
111 
113 {
114  if ( !m_pLineEdit->validate() ) return;
115  if ( m_pLineEdit->text().toUTF8().size() < 1 ) return;
116  isEmailExistInLdap(m_pLineEdit->text().toUTF8());
117 }
118 
120 {
121  gdCLdapServer m_cLdapServer;
122  m_cLdapServer.strServer = asString(option("ldapServer")).narrow();
123  m_cLdapServer.strDisplayName = asString(option("ldapName")).toUTF8();
124  m_cLdapServer.strLogon = asString(option("ldapLogon")).toUTF8();
125  m_cLdapServer.strPassword = asString(option("ldapSecret")).toUTF8();
126  if ( m_cLdapServer.TryServer() )
127  WApplication::instance()->log("notice") << " WsNewsLetter::isEmailExistInLdap() Ldap try ok !";
128  else {
129  std::string error = "WsNewsLetter::isEmailExistInLdap() Ldap try not ok !";
130  WApplication::instance()->log("notice") << error;
131  //TODO Change to ERROR class
132  wApp->setInternalPath("/ws/Errors/ServerTempUnavailable.fhtml", true);
133  return ldapError;
134  }
135  gdCLdapAttributes cWitchAttrs;
136  cWitchAttrs.push_back(new gdCLdapAttribute("givenName"));
137  cWitchAttrs.push_back(new gdCLdapAttribute("sn"));
138  cWitchAttrs.push_back(new gdCLdapAttribute("mail"));
139  cWitchAttrs.push_back(new gdCLdapAttribute("dn"));
140  gdCLdap m_cLdap;
141  m_cLdap.setDebugging(true);
142  m_cLdap.setManageDSAIT(true);
143  gdCLdapFilter cFilter;
144  cFilter.pServer = &m_cLdapServer;
145  cFilter.strInitialSearchBase = asString(option("ldapBase")).toUTF8();
146  cFilter.nScope = LDAP_SCOPE_SUB;
147  cFilter.strFilter = "(&(mail=" + email + "))";
148  gdCLdapEntries cEntries;
149  if ( !m_cLdap.GetInfo(cFilter, cWitchAttrs, cEntries) && m_cLdap.GetLastError() != CLdapErrNoEntries ) {
150  std::string notice = "WsNewsLetter::isEmailExistInLdap() cannot get ldap info or no entries!";
151  WApplication::instance()->log("notice") << notice;
152  //TODO Change to ERROR class
153  wApp->setInternalPath("/ws/Errors/ServerTempUnavailable.fhtml", true);
154  return ldapError;
155  }
156  // Email not available
157  if ( cEntries.size() == 0 ) {
158  emailNotInLdap(email);
159  return emailNotAvailable;
160  }
161  // Multiple email entries
162  if ( cEntries.size() > 1 ) {
163  multipleEmail(email);
164  return emailMultiple;
165  }
166  std::string sGivenName;
167  std::string sSN;
168  std::string sEmail;
169  std::string sDn;
170  for (int nAttr = 0; nAttr < cEntries[0]->Attrs.size(); ++nAttr) {
171  if ( cEntries[0]->Attrs[nAttr]->Attr == "sn" ) sSN = cEntries[0]->Attrs[nAttr]->Values[0]->ToStr();
172  if ( cEntries[0]->Attrs[nAttr]->Attr == "givenName" ) sGivenName = cEntries[0]->Attrs[nAttr]->Values[0]->ToStr();
173  if ( cEntries[0]->Attrs[nAttr]->Attr == "mail" ) sEmail = cEntries[0]->Attrs[nAttr]->Values[0]->ToStr();
174  if ( cEntries[0]->Attrs[nAttr]->Attr == "dn" ) sDn = cEntries[0]->Attrs[nAttr]->Values[0]->ToStr();
175  }
176  gdCLdapEntry entry;
177  entry.Dn = sDn;
178  gdCLdapAttribute updateAttr("EurListsMember");
179  updateAttr.bNewAttribute = true; // false destroy all existing values, true add a new one, in all case if the attribute does not exist it is added
180  updateAttr.addValue("Newsletter03");
181  // if the value exist : we receive error 312 "Type of value exists"
182  if ( !m_cLdapServer.UpdateAttribute(entry, updateAttr) )
183  wApp->log("notice") << "WsNewsLetter::isEmailExistInLdap() Cannot update ldap entry : " << sDn << "Contain a correct value";
184  else
185  wApp->log("notice") << "WsNewsLetter::isEmailExistInLdap() Ldap entry : " << sDn << " correctly updated !";
186 }
187 
188 void WsNewsLetter::multipleEmail(const std::string& email)
189 {
190  wApp->log("notice") << "WsNewsLetter::emailMultiple() email " << email;
191  std::string sTo = asString(option("NLEmailTo")).toUTF8();
192  std::string sSign = asString(option("NLSignature")).toUTF8();
193  std::string sSubject = "Muliple email detection when registering a NewsLetter";
194  std::string sBody = "Dear web administrator,<br /><br /> pending a check of the email <b>"
195  + email
196  + "</b> I detect a multiple entry on our LDAP database,<br />"
197  + " please check which correct action is required and process a manual response to our client<br /><br />"
198  + "Thanks in advance.<br/><br/>"
199  + sSign;
200  std::string sBodyPlain = "Dear web administrator,\n\npending a check of the email *"
201  + email
202  + "* I detect a multiple entry on our LDAP database,\n"
203  + " please check which correct action is required and process a manual response to our client\n\n"
204  + "Thanks in advance.\n\n"
205  + sSign;
206  sendEmail(sTo, sSubject, sBody, sBodyPlain);
207 }
208 
209 void WsNewsLetter::sendEmail(const std::string& email, const std::string& sSubject, const std::string& sBody, const std::string& sBodyPlain)
210 {
211  std::string sSmtpServer = asString(option("smtpServer")).toUTF8();
212  std::string sFrom = asString(option("NLEmailFrom")).toUTF8();
213  Mail::Message message;
214  message.setFrom(Mail::Mailbox(sFrom));
215  if ( email.size() > 0 )
216  message.addRecipient(Mail::To, Mail::Mailbox(email));
217  message.setSubject(sSubject);
218  message.setBody("No html renderer in your mail client ");
219  message.addHtmlBody (sBodyPlain);
220  Mail::Client client;
221  //client.connect(sSmtpServer);
222  client.connect("localhost");
223  client.send(message);
224  /*
225  std::string sSmtpServer = asString(option("smtpServer")).toUTF8();
226  std::string sFrom = asString(option("NLEmailFrom")).toUTF8();
227  vmime::platformDependant::setHandler<vmime::platforms::posix::posixHandler>();
228  try {
229  vmime::messageBuilder mb;
230  // Fill in the basic fields
231  mb.setExpeditor(vmime::mailbox(sFrom));
232  vmime::addressList to;
233  to.appendAddress(vmime::create <vmime::mailbox>(email));
234  mb.setRecipients(to);
235  mb.setSubject(vmime::text(sSubject));
236  // Message body
237  mb.constructTextPart(vmime::mediaType(vmime::mediaTypes::TEXT, vmime::mediaTypes::TEXT_HTML));
238  vmime::ref<vmime::htmlTextPart> textPart = mb.getTextPart().dynamicCast<vmime::htmlTextPart>();
239  textPart->setCharset(vmime::charsets::UTF_8);
240  textPart->setText(vmime::create<vmime::stringContentHandler>(sBody));
241  textPart->setPlainText(vmime::create<vmime::stringContentHandler>(sBodyPlain));
242  // wApp->log("notice") << "WsNewsLetter::emailMultiple() plain text end smtpserver = " << sSmtpServer;
243  vmime::ref<vmime::message> msg = mb.construct();
244  vmime::ref<vmime::net::session> sess = vmime::create<vmime::net::session>();
245  vmime::utility::url url(sSmtpServer);
246  vmime::ref<vmime::net::transport> tr = sess->getTransport(url);
247  tr->connect();
248  tr->send(msg);
249  tr->disconnect();
250  }
251  // VMime exception
252  catch (vmime::exception& e) {
253  std::cout << "vmime::exception: " << e.what() << std::endl;
254  throw;
255  }
256  // Standard exception
257  catch (std::exception& e) {
258  std::cout << "std::exception: " << e.what() << std::endl;
259  //throw;
260  }
261  */
262 }
263 
264 void WsNewsLetter::registerValidEmail(const std::string& email)
265 {
266 }
267 
268 // Implemantation from EMWEB
269 void WsNewsLetter::emailNotInLdap(const std::string& email)
270 {
271  std::string random = WRandom::generateId(16);
272  Auth::SHA1HashFunction hf;
273  std::string hash = hf.compute(random, std::string());
274  bool bMatchEmail = false;
275  {
276  dbo::Transaction transaction(session_);
277  EmailTokens eTokens = session_.find<EmailToken>().where("email = ?").bind(email);
278  if ( eTokens.size() != 0 ) {
279  std::string text = "Email is already in db, nothing to do !";
280  new WText(text, this);
281  wApp->log("notice") << "WsNewsLetter::emailNotInLdap() email exist in database " << email;
282  bMatchEmail = true;
283  } else {
284  EmailToken* eToken = new EmailToken();
285  eToken->email = email;
286  eToken->token = hash;
287  eToken->currentDate = WDate::currentDate();
288  eToken->registered = 0;
289  session_.add(eToken);
290  //TODO Add error Page
291  wApp->log("notice") << "WsNewsLetter::emailNotInLdap() email does not exist in database " << email << " token = " << random << " hash = " << hash;
292  }
293  }
294  if ( bMatchEmail ) {
295  wApp->setInternalPath("/ws/Errors/AlreadyInDb.fhtml", true);
296  return;
297  }
298  std::string sSubject = asString(option("NLSubject")).toUTF8();
299  std::string sBody = asString(option("NLBody")).toUTF8();
300  std::string sBodyPlain = asString(option("NLBodyPlain")).toUTF8();
301  std::string sServerUrl = WsGlobalProperties::instance()->get("global", "serverUrl", "http://localhost");
302  std::string url = sServerUrl + "/Newsletter/Subscribe/" + random;
303  wApp->log("notice") << "WsNewsLetter::emailNotInLdap() url created = " << url;
304  sBody += "<a href=\"" + url + "\">Register</a>";
305  sBodyPlain += url;
306  sendEmail(email, sSubject, sBody, sBodyPlain);
307  wApp->setInternalPath("/ws/ThanksSubscription.fhtml", true);
308 }
309 
310 std::string WsNewsLetter::checkPath(const std::string& path)
311 {
312  if ( path.compare(0, 22, "/Newsletter/Subscribe/") != 0 ) return path;
313  std::string token = path;
314  boost::algorithm::replace_all(token, "/Newsletter/Subscribe/", "");
315  initDB();
316  Auth::SHA1HashFunction hf;
317  std::string hash = hf.compute(token, std::string());
318  dbo::Transaction transaction(session_);
319  EmailTokens eTokens = session_.find<EmailToken>().where("token = ?").bind(hash);
320  std::string retPage;
321  if ( eTokens.size() == 0 )
322  retPage = "/ws/Errors/NotInDB.fhtml";
323  else {
324  EmailTokens::const_iterator i = eTokens.begin();
325  if ( (*i)->registered == 0 ) {
326  // TODO : How to set the email in the form ?
327  // the form save the data.
328  retPage = "/ws/Subscribe.form";
329  i->modify()->registered++;
330  } else {
331  retPage = "/ws/Errors/AlreadyRegistered.fhtml";
332  // TODO : Update value ?
333  }
334  }
335  wApp->setInternalPath(retPage, true);
336  return retPage;
337 }
338 
dbo::backend::Sqlite3 * sqlite3_
Definition: WsNewsLetter.h:51
Wt::Dbo::collection< Wt::Dbo::ptr< EmailToken > > EmailTokens
Definition: EmailToken.h:33
void emailNotInLdap(const std::string &email)
WsNewsLetter(Wt::WContainerWidget *parent=0)
CTor.
a wittyShare module
emailAvailability isEmailExistInLdap(const std::string &email)
int registered
Definition: EmailToken.h:23
std::string token
Definition: EmailToken.h:21
void registerValidEmail(const std::string &email)
Wt::WDate currentDate
Definition: EmailToken.h:22
emailAvailability
descripte the result of the Ldap query
Definition: WsNewsLetter.h:29
std::string checkPath(const std::string &currentPath)
const boost::any & option(const std::string &attribute) const
Get an options value.
Definition: WsOption.cpp:62
void doLineEditChanged()
std::string get(const std::string &section, const std::string &id, const std::string &def)
std::string email
Definition: EmailToken.h:20
Wt::WLineEdit * m_pLineEdit
Definition: WsNewsLetter.h:48
static WsGlobalProperties * instance()
void sendEmail(const std::string &email, const std::string &sSubject, const std::string &sBody, const std::string &sBodyPlain)
void doSubscribe()
dbo::Session session_
Definition: WsNewsLetter.h:50
void multipleEmail(const std::string &email)
Wt::WPushButton * m_pButSubscribe
Definition: WsNewsLetter.h:49