Commit d8d9e300 by Dirk Benkert

added email invitations and forgot password

parent 8f095c68
......@@ -56,10 +56,20 @@ rename config/autoload/local.php.dist to config/autoload/local.php and edit with
),
),
),
'emails' => array(
'sender' => array(
'name' => 'NAME',
'email' => 'email@your-domain.com',
),
'default-data' => array(
'base-url' => 'http://www.your-domain.com/share',
)
)
```
enter you database credentials and modify the path where the uploaded files are stored if necessary.
Make shure "physical-path" is writeable.
Make shure "physical-path" is writeable. Modify sender email and name for emails sent during invitaiton and
password resets. Also modify base-url to point to the appliation on your domain.
You can call the cleanup task via cron or by manually executing on the console.
```
......@@ -87,7 +97,7 @@ To validate the setup of run
php index.php validate-setup
```
## Design
## Customizing
To modify the design, make your changes to resources/less/globals.less. You need node.js and gulp to build the
CSS and Javascript after that. Install from https://nodejs.org/ and follow the instructions on
https://github.com/gulpjs/gulp/blob/master/docs/getting-started.md
......@@ -100,4 +110,7 @@ npm install
gulp
```
To change the footer links, modify ./footerLinks.json
\ No newline at end of file
To change the footer links, modify ./footerLinks.json
If you want to customize the email templates used for invitation and forgot password emails see
./mustache/forgotpassword.mustache
./mustache/invite.mustache
\ No newline at end of file
......@@ -39,4 +39,14 @@ return array(
),
),
),
'emails' => array(
//'testmode' => true, // disables email notification e.g. for local development and testing
'sender' => array(
'name' => 'NAME',
'email' => 'email@your-domain.com',
),
'default-data' => array(
'base-url' => 'https://www.your-domain.com/path',
)
)
);
......@@ -165,4 +165,10 @@ return array(
'Zend\Session\Validator\HttpUserAgent',
),
),
'emails' => array(
'subjects' => array(
'forgotPassword' => 'Forgot Password?',
'invite' => 'You have been invited to a shared folder.',
),
),
);
......@@ -36,6 +36,7 @@ use Zend\Json\Json;
use Zend\View\Model\ViewModel;
use Application\Form\FolderForm;
use Application\Form\ForgotPasswordForm;
use Application\Service\ForgotPassword;
class FormController extends ControllerAbstract {
......@@ -46,9 +47,11 @@ class FormController extends ControllerAbstract {
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
$service = new ForgotPassword($this->getServiceLocator());
$service->run($form->getData());
return $this->getResponse()->setContent(Json::encode(array(
'status' => 'success',
'target' => 'folder'
'status' => 'success',
)));
} else {
error_log(print_r($request->getPost(), true));
......@@ -61,25 +64,4 @@ class FormController extends ControllerAbstract {
$viewModel->setTerminal(true);
return $viewModel;
}
public function folderAction() {
$form = new FolderForm();
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
return $this->getResponse()->setContent(Json::encode(array(
'status' => 'success',
'target' => 'folder'
)));
}
}
$viewModel = new ViewModel(array(
'form' => $form,
));
$viewModel->setTemplate('application/dialog/newfolder.phtml');
$viewModel->setTerminal(true);
return $viewModel;
}
}
<?php
/**
* Dirk Benkert (https://www.dirk-benkert.de/)
*
* @link https://gitlab.dirk-benkert.de/zf2/share for the canonical source repository
* @copyright Copyright (c) 2015 Dirk Benkert (https://www.dirk-benkert.de)
* @license Apache License Version 2.0
*
* Copyright 2015 Dirk Benkert
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Description for ForgotPassword Service
*
* @package Application_Service
* @author Dirk Benkert <dirk.benkert.extern@vogel-druck.de>
* @copyright Copyright (c) Vogel-Druck
* @version 1.0
*/
namespace Application\Service;
use Zend\ServiceManager\ServiceLocatorInterface;
use Application\Entity\User;
use Application\Service\NotificationEmail;
use Application\Service\Password;
class ForgotPassword extends AbstractService {
protected $notificationEmail = null;
public function __construct(ServiceLocatorInterface $serviceManager) {
$this->setServiceLocator($serviceManager);
$this->notificationEmail = new NotificationEmail('forgotPassword', $this->getServiceLocator());
}
public function run($formData) {
$user = $this->getEntityManager()->getRepository('Application\Entity\User')->findOneBy(array(
'email' => $formData['targetEmail'],
));
if ($user) {
$generator = new Password();
$newPassword = $generator->generate();
$user->setPassword($newPassword);
$this->notificationEmail->addRecipient($user->email);
$this->notificationEmail->setData(array(
'new-password' => $newPassword,
'email' => $user->email
));
$this->notificationEmail->send();
$this->getEntityManager()->persist($user);
$this->getEntityManager()->flush();
}
}
}
\ No newline at end of file
<?php
/**
* Dirk Benkert (https://www.dirk-benkert.de/)
*
* @link https://gitlab.dirk-benkert.de/zf2/share for the canonical source repository
* @copyright Copyright (c) 2015 Dirk Benkert (https://www.dirk-benkert.de)
* @license Apache License Version 2.0
*
* Copyright 2015 Dirk Benkert
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Description for NotificationEmail Service
*
* @package Application_Service
* @author Dirk Benkert <dirk.benkert.extern@vogel-druck.de>
* @copyright Copyright (c) Vogel-Druck
* @version 1.0
*/
namespace Application\Service;
use Zend\ServiceManager\ServiceLocatorInterface;
use \Mustache_Engine as Mustache;
use Zend\Mail;
use Zend\Config\Reader\Ini;
class NotificationEmail extends AbstractService {
/**
* data to be parsed by mustache template engine
*
* @var array
*/
protected $data;
/**
* Mustache template engine
*
* @var \Mustache_Engine
*/
protected $mustache;
/**
* identifies email template. Identifier is used as section name in email.ini and template name in view/mustache folder
*
* @var string
*/
protected $identifier;
/**
* email config from config/email.ini
*
* @var array
*/
protected $config;
/**
* list of recipients
*
* @var array
*/
protected $recipients = array();
/**
* The constructor
*
* @return void
* @throws \RuntimeException
*/
public function __construct($identifier, \Zend\ServiceManager\ServiceLocatorInterface $serviceLocator) {
parent::__construct($serviceLocator);
$this->mustache = new Mustache();
$config = $this->getServiceLocator()->get('Config');
if (!isset($config['emails'])) {
throw new \RuntimeException('email configuration missing check README or local.php.dist for an example.');
}
$this->config = $config['emails'];
$this->setIdentifier($identifier);
}
public function send() {
if (!$this->getIdentifier()) {
throw new \RuntimeException('no identifier set before calling run on NotificationEmail service.');
}
$this->template = $template = getcwd() . '/mustache/'.$this->getIdentifier().'.mustache';
if (!file_exists($this->template)) {
throw new \RuntimeException($this->template . ' not found.');
}
$config = $this->getConfig();
$mail = new Mail\Message();
$mail->setEncoding("UTF-8");
$mail->setBody($this->renderMessage());
$mail->setFrom($config['sender']['email'], $config['sender']['name']);
foreach ($this->getRecipients() as $recipient) {
$mail->addTo($recipient);
}
$mail->setSubject($config['subjects'][$this->getIdentifier()]);
$transport = new Mail\Transport\Sendmail('-f'.$config['sender']['email']);
if (!isset($this->config['testmode'])) {
$transport->send($mail);
}
}
public function renderMessage() {
$config = $this->getConfig();
return $this->mustache->render(
file_get_contents($this->template),
$this->getData()
);
}
public function getDefaultData() {
$config = $this->getConfig();
return $config['default-data'];
}
/**
* getter
*
* @return array
*/
public function getConfig() {
return $this->config;
}
/**
* getter
*
* @return array
*/
public function getData() {
return array_merge($this->data, $this->getDefaultData());
}
/**
* getter
*
* @return string
*/
public function getIdentifier() {
return $this->identifier;
}
/**
* getter
*
* @return array
*/
public function getRecipients() {
return $this->recipients;
}
/**
* setter
*
* @param array $data
*/
public function setData($data) {
$this->data = $data;
}
/**
* setter
*
* @param string $identifier
*/
public function setIdentifier($identifier) {
$this->identifier = $identifier;
}
/**
* array or string of recipients
*
* @param mixed $recipient
*/
public function setRecipients($recipient) {
if (!is_array($recipient)) {
$recipient = array($recipient);
}
$this->recipients = $recipient;
}
/**
* add recpient
*
* @param string $recipient
*/
public function addRecipient($recipient) {
$this->recipients[] = $recipient;
}
}
......@@ -24,6 +24,7 @@
namespace Application\Service;
use Application\Entity\User as UserEntity;
use Application\Service\NotificationEmail;
use Zend\Validator\EmailAddress;
class User extends AbstractService {
......@@ -40,23 +41,27 @@ class User extends AbstractService {
public function saveFolderUsers($userlist, $folderId) {
$folder = $this->getEntityManager()->find('Application\Entity\Folder', $folderId);
$existingUsers = $folder->users;
// remove all previously added storages
$folder->users = null;
$this->getEntityManager()->persist($folder);
$validator = new EmailAddress();
$newUsers = array();
foreach ($userlist as $userid => $value) {
$user = $this->getEntityManager()->find('Application\Entity\User', $userid);
$password = false;
if (!is_numeric($userid)) {
if($validator->isValid($userid)) {
$user = new UserEntity();
$service = new Password();
$password = $service->generate();
$user->setData(array(
'email' => $userid,
'password' => $service->generate(),
'password' => $password,
'isadmin' => false,
'caninvite' => false,
'cancreatefolders' => false,
......@@ -74,11 +79,50 @@ class User extends AbstractService {
}
if ($user && $userid == $value) {
$newUsers[$userid] = array(
'email' => $user->email,
'password' => $password
);
$folder->addUser($user);
}
}
$this->getEntityManager()->persist($folder);
$this->getEntityManager()->flush();
$this->sendInvites($existingUsers, $newUsers);
}
public function sendInvites($oldUserList, $newUserList) {
$notificationService = new NotificationEmail('invite', $this->getServiceLocator());
$userIds = array_keys($newUserList);
foreach ($oldUserList as $user) {
if (in_array($user->id, $userIds)) {
unset($newUserList[$user->id]);
}
}
foreach ($newUserList as $invitee) {
$notificationService->addRecipient($invitee['email']);
$notificationService->setData($this->getData($invitee));
$notificationService->send();
}
}
public function getData($invitee) {
$text = 'Use ' . $invitee['email'] . ' to login.';
$authService = $this->getServiceLocator()->get('Zend\Authentication\AuthenticationService');
$identity = $authService->getIdentity();
if (false !== $invitee['password']) {
$text .= PHP_EOL . 'Password: ' . $invitee['password'];
}
return array(
'invitor' => $identity->email,
'text' => $text,
);
}
}
......@@ -27,7 +27,7 @@
</div>
<div class="mod modUserNew" >
<div class="inner background-white">
<form method="post" action="<?php echo $this->url('application/default', array('controller' => 'form', 'action' => 'user')); ?>">
<form method="post" action="<?php echo $this->url('application/default', array('controller' => 'json', 'action' => 'savefolderusers')); ?>">
<div class="modal-body">
<div class="input-group">
<span class="input-group-addon" id="basic-addon1">@</span>
......
Hello,
your password for {{base-url}} has been reset.
To login use the following password: {{new-password}}
Please dont forget to change your password after login.
Thank you for using {{base-url}}
Hello,
you have been invited to a shared folder at {{base-url}} by {{invitor}}.
{{text}}
Thank you for using {{base-url}}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment