PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Lampcms/Controllers/Register.php

https://github.com/snytkine/LampCMS
PHP | 354 lines | 131 code | 55 blank | 168 comment | 5 complexity | d392032e48953079e532453603108d80 MD5 | raw file
Possible License(s): LGPL-3.0
  1. <?php
  2. /**
  3. *
  4. * License, TERMS and CONDITIONS
  5. *
  6. * This software is licensed under the GNU LESSER GENERAL PUBLIC LICENSE (LGPL) version 3
  7. * Please read the license here : http://www.gnu.org/licenses/lgpl-3.0.txt
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * 3. The name of the author may not be used to endorse or promote products
  17. * derived from this software without specific prior written permission.
  18. *
  19. * ATTRIBUTION REQUIRED
  20. * 4. All web pages generated by the use of this software, or at least
  21. * the page that lists the recent questions (usually home page) must include
  22. * a link to the http://www.lampcms.com and text of the link must indicate that
  23. * the website's Questions/Answers functionality is powered by lampcms.com
  24. * An example of acceptable link would be "Powered by <a href="http://www.lampcms.com">LampCMS</a>"
  25. * The location of the link is not important, it can be in the footer of the page
  26. * but it must not be hidden by style attributes
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
  29. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  30. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  31. * IN NO EVENT SHALL THE FREEBSD PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY
  32. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  33. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  34. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  35. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  36. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  37. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. * This product includes GeoLite data created by MaxMind,
  40. * available from http://www.maxmind.com/
  41. *
  42. *
  43. * @author Dmitri Snytkine <cms@lampcms.com>
  44. * @copyright 2005-2012 (or current year) Dmitri Snytkine
  45. * @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU LESSER GENERAL PUBLIC LICENSE (LGPL) version 3
  46. * @link http://www.lampcms.com Lampcms.com project
  47. * @version Release: @package_version@
  48. *
  49. *
  50. */
  51. namespace Lampcms\Controllers;
  52. use \Lampcms\WebPage;
  53. use \Lampcms\String;
  54. use \Lampcms\Cookie;
  55. use \Lampcms\Request;
  56. use \Lampcms\Captcha\Captcha;
  57. use \Lampcms\Mongo\Schema\User as Schema;
  58. use \Lampcms\Acl\Role;
  59. /**
  60. * Main class for creating new account
  61. * for a new user who is registered
  62. * with just email address (no 3rd party API login)
  63. *
  64. * @todo move as many methods as possible to
  65. * a wrapper class so that it could be called
  66. * not only as a web page Controller
  67. * but also from the API
  68. * Later it will be easy to reuse if we have the API
  69. *
  70. * @author Dmitri Snytkine
  71. *
  72. */
  73. class Register extends WebPage
  74. {
  75. protected $permission = 'register';
  76. protected $layoutID = 1;
  77. /**
  78. * Object Regform;
  79. *
  80. * @var object Forms\Regform
  81. */
  82. protected $Form;
  83. /**
  84. * New temporary password of new user
  85. *
  86. * @var string
  87. */
  88. protected $pwd;
  89. /**
  90. * Username of new user
  91. *
  92. * @var string
  93. */
  94. protected $username;
  95. /**
  96. *
  97. * Email address of new user
  98. *
  99. * @var string
  100. */
  101. protected $email;
  102. /**
  103. * Object represents on record in EMAILS collection
  104. *
  105. * @var object of type \Lampcms\Mongo\Doc
  106. */
  107. protected $oEmail;
  108. protected function main()
  109. {
  110. $this->aPageVars['title'] = '@@Create New Account@@';
  111. /**
  112. * Don't bother with token
  113. * for this form.
  114. * It uses captcha, so allow
  115. * users to submit without token
  116. */
  117. $this->Form = new \Lampcms\Forms\Regform($this->Registry, false);
  118. $this->Form->setVar('action', 'register');
  119. /**
  120. * Set divID to registration because otherwise
  121. * it is default to 'regform' which causes
  122. * the whole form's div to be turned into
  123. * a modal which is used in quickReg or Join controllers
  124. * but for this controller we want a regular web page,
  125. * no modals, no Ajax
  126. *
  127. * Also set className to 'registration' because it defaults
  128. * to yui-pre-content which makes the whole div hidden
  129. * This is a trick for adding something that later is turned
  130. * into modal, but we don't need it for this page
  131. */
  132. $this->Form->setVar('divID', 'registration');
  133. $this->Form->setVar('className', 'registration');
  134. $this->Form->setVar('header2', '@@Create New Account@@');
  135. $this->Form->setVar('button', '<input name="submit" value="@@Register@@" type="submit" class="btn btn-m">');
  136. $this->Form->setVar('captcha', Captcha::factory($this->Registry->Ini)->getCaptchaBlock());
  137. $this->Form->setVar('title', '@@Create an Account@@');
  138. $this->Form->setVar('titleBar', '');
  139. if ($this->Form->isSubmitted() && $this->Form->validate()) {
  140. $this->getSubmittedValues()
  141. ->createNewUser()
  142. ->createEmailRecord()
  143. ->sendActivationEmail();
  144. $this->aPageVars['body'] = '<div id="tools" class="larger">@@Welcome to out site. We have just emailed your your account activation link@@</div>';
  145. } else {
  146. $this->aPageVars['body'] = '<div id="userForm" class="frm1">' . $this->Form->getForm() . '</div>';
  147. }
  148. }
  149. /**
  150. * Init instance variables
  151. * $this->username, $this->email and $this->pwd
  152. *
  153. * @return object $this
  154. */
  155. protected function getSubmittedValues()
  156. {
  157. $this->username = $this->Form->getSubmittedValue('username');
  158. $this->pwd = \Lampcms\String::makePasswd();
  159. $this->email = \mb_strtolower($this->Form->getSubmittedValue('email'));
  160. return $this;
  161. }
  162. /**
  163. *
  164. * Create new record in USERS collection,
  165. *
  166. * @return object $this
  167. */
  168. protected function createNewUser()
  169. {
  170. $coll = $this->Registry->Mongo->USERS;
  171. $coll->ensureIndex(array(Schema::USERNAME_LOWERCASE => 1), array('unique' => true));
  172. /**
  173. * Cannot make email unique index because external users
  174. * don't have email, and then value counts as null
  175. * and multiple null values count as duplicate!
  176. *
  177. */
  178. $coll->ensureIndex(array(Schema::EMAIL => 1));
  179. $coll->ensureIndex(array(Schema::ROLE => 1));
  180. /**
  181. * Indexes for managing 3 types
  182. * of following
  183. */
  184. $coll->ensureIndex(array('a_f_t' => 1));
  185. $coll->ensureIndex(array('a_f_u' => 1));
  186. $coll->ensureIndex(array('a_f_q' => 1));
  187. $sid = Cookie::getSidCookie();
  188. if (false !== $tzn = Cookie::get('tzn')) {
  189. $timezone = $tzn;
  190. } else {
  191. $timezone = $this->Registry->Ini->SERVER_TIMEZONE;
  192. }
  193. $aData[Schema::USERNAME] = $this->username;
  194. $aData[Schema::USERNAME_LOWERCASE] = \mb_strtolower($this->username);
  195. $aData[Schema::EMAIL] = $this->email;
  196. $aData[Schema::SID] = (false !== $sid) ? $sid : \Lampcms\String::makeSid();
  197. $aData[Schema::ROLE] = $this->getRole();
  198. $aData[Schema::TIMEZONE] = $timezone;
  199. $aData[Schema::PASSWORD] = String::hashPassword($this->pwd);
  200. $aData[Schema::REGISTRATION_TIMESTAMP] = time();
  201. $aData[Schema::REGISTRATION_TIME] = date('r');
  202. $aData[Schema::FIRST_VISIT_TIMESTAMP] = (false !== $intFv = \Lampcms\Cookie::getSidCookie(true)) ? $intFv : time();
  203. $aData[Schema::LOCALE] = $this->Registry->Locale->getLocale();
  204. /**
  205. * Initial reputation is always 1
  206. *
  207. * @var int
  208. */
  209. $aData[Schema::REPUTATION] = 1;
  210. $aUser = \array_merge($this->Registry->Geo->Location->data, $aData);
  211. d('aUser: ' . \json_encode($aUser));
  212. $User = \Lampcms\User::userFactory($this->Registry, $aUser);
  213. $User->save();
  214. d('new user _id: ' . $User['_id']);
  215. $this->processLogin($User);
  216. \Lampcms\PostRegistration::createReferrerRecord($this->Registry, $User);
  217. return $this;
  218. }
  219. /**
  220. * Normally the role of newly registered user
  221. * is 'unactivated' unless
  222. * the email address matches that of the EMAIL_ADMIN
  223. * in settings, in which case the account will
  224. * automatically become an administrator account
  225. *
  226. *
  227. * @internal param string $email email address
  228. * @return string
  229. */
  230. protected function getRole()
  231. {
  232. return ($this->Registry->Ini->EMAIL_ADMIN === $this->email) ? Role::ADMINISTRATOR : Role::UNACTIVATED;
  233. }
  234. /**
  235. * Created a new record in EMAILS collection
  236. *
  237. * @param null $userId
  238. *
  239. * @return object $this
  240. */
  241. protected function createEmailRecord($userId = null)
  242. {
  243. $coll = $this->Registry->Mongo->EMAILS;
  244. $coll->ensureIndex(array(Schema::EMAIL => 1), array('unique' => true));
  245. $uid = (\is_numeric($userId)) ? $userId : $this->Registry->Viewer->getUid();
  246. $a = array(
  247. Schema::EMAIL => $this->email,
  248. 'i_uid' => $uid,
  249. 'has_gravatar' => \Lampcms\Gravatar::factory($this->email)->hasGravatar(),
  250. 'ehash' => \hash('md5', $this->email),
  251. 'i_code_ts' => time(),
  252. 'code' => \substr(hash('md5', \uniqid(\mt_rand())), 0, 12));
  253. $this->oEmail = \Lampcms\Mongo\Doc::factory($this->Registry, 'EMAILS', $a);
  254. $res = $this->oEmail->save();
  255. d('$res: ' . $res);
  256. return $this;
  257. }
  258. /**
  259. * Make account activation link
  260. *
  261. * @return string url of account activation link
  262. */
  263. protected function makeActivationLink()
  264. {
  265. $routerCallback = $this->Registry->Router->getCallback();
  266. $uri = $routerCallback('{_WEB_ROOT_}/{_activate_}');
  267. d('uri: ' . $uri);
  268. $tpl = $this->Registry->Ini->SITE_URL . $uri . '/%d/%s';
  269. $link = \sprintf($tpl, $this->oEmail['_id'], $this->oEmail['code']);
  270. d('activation link: ' . $link);
  271. return $link;
  272. }
  273. /**
  274. * Send registration email to new user
  275. * Email will contain activation link
  276. * and instructions to activate the account
  277. *
  278. * @return Register
  279. */
  280. protected function sendActivationEmail()
  281. {
  282. $Tr = $this->Registry->Tr;
  283. $activationLink = $this->makeActivationLink();
  284. $siteName = $this->Registry->Ini->SITE_NAME;
  285. $body = $Tr->get('email.body.registration', array(
  286. '{site_title}' => $siteName,
  287. '{username}' => $this->username,
  288. '{password}' => $this->pwd,
  289. '{link}' => $activationLink)
  290. );
  291. $body = \Lampcms\Utf8String::leftAlign($body, 2);
  292. $subject = $Tr->get('email.subject.registration', array('{site_title}' => $siteName));
  293. /**
  294. * By default Mailer::mail sends email from shutdown function (returns immediately, sends later)
  295. */
  296. $this->Registry->Mailer->mail($this->email, $subject, $body);
  297. return $this;
  298. }
  299. }