From e515d58b6c7115950e01e0ada93d605c6a5b7dcb Mon Sep 17 00:00:00 2001 From: dartcafe Date: Sat, 4 Jul 2020 09:00:55 +0200 Subject: [PATCH 1/6] track invitation sent in share --- lib/Db/Share.php | 8 +- .../Version0105Date20200704084037.php | 78 +++++++++++++++++++ lib/Service/MailService.php | 2 + lib/Service/ShareService.php | 5 +- 4 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 lib/Migration/Version0105Date20200704084037.php diff --git a/lib/Db/Share.php b/lib/Db/Share.php index d9e9587c3..1a3042d22 100644 --- a/lib/Db/Share.php +++ b/lib/Db/Share.php @@ -41,6 +41,8 @@ * @method void setUserId(string $value) * @method string getUserEmail() * @method void setUserEmail(string $value) + * @method integer getInvitationSent() + * @method void setInvitationSent(integer $value) */ class Share extends Entity implements JsonSerializable { @@ -59,6 +61,9 @@ class Share extends Entity implements JsonSerializable { /** @var string $userEmail */ protected $userEmail; + /** @var string $invitationSent */ + protected $invitationSent; + public function jsonSerialize() { return [ @@ -68,7 +73,8 @@ public function jsonSerialize() { 'pollId' => intval($this->pollId), 'userId' => $this->userId, 'userEmail' => $this->userEmail, - 'displayName' => $this->getDisplayName() + 'displayName' => $this->getDisplayName(), + 'invitationSent' => intval($this->invitationSent) ]; } diff --git a/lib/Migration/Version0105Date20200704084037.php b/lib/Migration/Version0105Date20200704084037.php new file mode 100644 index 000000000..6bdbf941b --- /dev/null +++ b/lib/Migration/Version0105Date20200704084037.php @@ -0,0 +1,78 @@ + + * + * @author René Gieling + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Polls\Migration; + +use Doctrine\DBAL\Types\Type; +use OCP\DB\ISchemaWrapper; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IConfig; +use OCP\IDBConnection; +use OCP\Migration\SimpleMigrationStep; +use OCP\Migration\IOutput; + +/** + * Installation class for the polls app. + * Initial db creation + */ +class Version0105Date20200704084037 extends SimpleMigrationStep { + + /** @var IDBConnection */ + protected $connection; + + /** @var IConfig */ + protected $config; + + /** + * @param IDBConnection $connection + * @param IConfig $config + */ + public function __construct(IDBConnection $connection, IConfig $config) { + $this->connection = $connection; + $this->config = $config; + } + + /** + * @param IOutput $output + * @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + * @since 13.0.0 + */ + public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + if ($schema->hasTable('polls_share')) { + $table = $schema->getTable('polls_share'); + if (!$table->hasColumn('invitation_sent')) { + $table->addColumn('invitation_sent', Type::INTEGER, [ + 'length' => 11, + 'notnull' => true, + 'default' => 0 + ]); + } + } + + return $schema; + } +} diff --git a/lib/Service/MailService.php b/lib/Service/MailService.php index b285b99b7..d1a73c3ab 100644 --- a/lib/Service/MailService.php +++ b/lib/Service/MailService.php @@ -300,6 +300,8 @@ public function sendInvitationMail($token) { $recipient['eMailAddress'], $recipient['displayName'] ); + $share->setInvitationSent(time()); + $this->shareMapper->update($share); $sentMails[] = $recipient; } catch (Exception $e) { $abortedMails[] = $recipient; diff --git a/lib/Service/ShareService.php b/lib/Service/ShareService.php index a7cf144bd..bdc4177ce 100644 --- a/lib/Service/ShareService.php +++ b/lib/Service/ShareService.php @@ -101,7 +101,6 @@ public function get($token) { * @param string $share * @return array */ - // TODO: Replace with $this->add and separate sending invitations public function write($pollId, $type, $userId, $userEmail = '') { if (!$this->acl->setPollId($pollId)->getAllowEdit()) { @@ -113,6 +112,7 @@ public function write($pollId, $type, $userId, $userEmail = '') { $this->share->setPollId($pollId); $this->share->setUserId($userId); $this->share->setUserEmail($userEmail); + $this->share->setInvitationSent(0); $this->share->setToken(\OC::$server->getSecureRandom()->generate( 16, ISecureRandom::CHAR_DIGITS . @@ -121,6 +121,7 @@ public function write($pollId, $type, $userId, $userEmail = '') { )); $this->share = $this->shareMapper->insert($this->share); + // TODO: Replace with $this->add and separate sending invitations $sendResult = $this->mailService->sendInvitationMail($this->share->getToken()); return [ @@ -147,6 +148,7 @@ public function add($pollId, $type, $userId, $userEmail = '') { $this->share->setPollId($pollId); $this->share->setUserId($userId); $this->share->setUserEmail($userEmail); + $this->share->setInvitationSent(0); $this->share->setToken(\OC::$server->getSecureRandom()->generate( 16, ISecureRandom::CHAR_DIGITS . @@ -191,6 +193,7 @@ public function createPersonalShare($token, $userName) { $this->share->setPollId($publicShare->getPollId()); $this->share->setUserId($userName); $this->share->setUserEmail(''); + $this->share->setInvitationSent(time()); return $this->shareMapper->insert($this->share); } elseif ($publicShare->getType() === 'email') { From f12db4606555121fc912a3185ad616c5dbdb057d Mon Sep 17 00:00:00 2001 From: dartcafe Date: Sun, 5 Jul 2020 15:30:05 +0200 Subject: [PATCH 2/6] extend controllers for indiviual invitation sending --- appinfo/routes.php | 2 ++ lib/Controller/ShareApiController.php | 22 +++++++++++++++ lib/Controller/ShareController.php | 37 ++++++++++++++++++------- lib/Service/MailService.php | 10 +++---- lib/Service/ShareService.php | 40 --------------------------- 5 files changed, 56 insertions(+), 55 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index 0259f841e..5dd97f7e6 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -65,6 +65,7 @@ ['name' => 'share#add', 'url' => '/share/add', 'verb' => 'POST'], ['name' => 'share#delete', 'url' => '/share/delete', 'verb' => 'POST'], ['name' => 'share#createPersonalShare', 'url' => '/share/create/s', 'verb' => 'POST'], + ['name' => 'share#sendInvitation', 'url' => '/share/send/{token}', 'verb' => 'POST'], // ['name' => 'share#getShares', 'url' => '/shares/get/{pollId}', 'verb' => 'GET'], // ['name' => 'share#get', 'url' => '/share/get/{token}', 'verb' => 'GET'], @@ -98,6 +99,7 @@ ['name' => 'share_api#get', 'url' => '/api/v1.0/share/{token}', 'verb' => 'GET'], ['name' => 'share_api#add', 'url' => '/api/v1.0/share', 'verb' => 'POST'], ['name' => 'share_api#delete', 'url' => '/api/v1.0/share/{token}', 'verb' => 'DELETE'], + ['name' => 'share_api#sendInvitation', 'url' => '/api/v1.0/share/send/{token}', 'verb' => 'POST'], ['name' => 'subscription_api#get', 'url' => '/api/v1.0/poll/{pollId}/subscription', 'verb' => 'GET'], ['name' => 'subscription_api#subscribe', 'url' => '/api/v1.0/poll/{pollId}/subscription', 'verb' => 'PUT'], diff --git a/lib/Controller/ShareApiController.php b/lib/Controller/ShareApiController.php index cceb7aa6d..3d7912da1 100644 --- a/lib/Controller/ShareApiController.php +++ b/lib/Controller/ShareApiController.php @@ -35,21 +35,25 @@ use OCP\AppFramework\Http\DataResponse; use OCA\Polls\Service\ShareService; +use OCA\Polls\Service\MailService; class ShareApiController extends ApiController { private $shareService; + private $mailService; /** * ShareController constructor. * @param string $appName * @param string $userId * @param IRequest $request + * @param MailService $mailService * @param ShareService $shareService */ public function __construct( string $appName, IRequest $request, + MailService $mailService, ShareService $shareService ) { parent::__construct($appName, @@ -58,6 +62,7 @@ public function __construct( 'Authorization, Content-Type, Accept', 1728000); $this->shareService = $shareService; + $this->mailService = $mailService; } /** @@ -120,6 +125,23 @@ public function add($pollId, $type, $userId = '', $userEmail = '') { } + /** + * SendInvitation + * Sent invitation mails for a share + * @NoAdminRequired + * @CORS + * @NoCSRFRequired + * @param string $token + * @return DataResponse + */ + public function sendInvitation($token) { + try { + return new DataResponse($this->mailService->sendInvitationMail($token), Http::STATUS_OK); + } catch (Exception $e) { + return new DataResponse(['error' => $e->getMessage()], $e->getStatus()); + } + } + /** * delete share * @NoAdminRequired diff --git a/lib/Controller/ShareController.php b/lib/Controller/ShareController.php index aa80cc3de..bd3dd187e 100644 --- a/lib/Controller/ShareController.php +++ b/lib/Controller/ShareController.php @@ -39,11 +39,13 @@ use OCA\Polls\Model\Acl; use OCA\Polls\Service\ShareService; +use OCA\Polls\Service\MailService; class ShareController extends Controller { private $logger; private $shareService; + private $mailService; private $userId; /** @@ -52,6 +54,7 @@ class ShareController extends Controller { * @param string $userId * @param IRequest $request * @param ILogger $logger + * @param MailService $mailService * @param ShareService $shareService */ public function __construct( @@ -59,12 +62,14 @@ public function __construct( $userId, IRequest $request, ILogger $logger, + MailService $mailService, ShareService $shareService ) { parent::__construct($appName, $request); $this->logger = $logger; $this->userId = $userId; $this->shareService = $shareService; + $this->mailService = $mailService; } /** @@ -75,21 +80,14 @@ public function __construct( * @param Array $share * @return DataResponse */ - public function add($pollId, $share) { - try { - $return = $this->shareService->write( - $pollId, - $share['type'], - $share['userId'], - isset($share['userEmail']) ? $share['userEmail'] : '' - ); - return new DataResponse($return, Http::STATUS_CREATED); + public function add($pollId, $type, $userId = '', $userEmail = '') { + try { + return new DataResponse(['share' => $this->shareService->add($pollId, $type, $userId, $userEmail)], Http::STATUS_CREATED); } catch (NotAuthorizedException $e) { return new DataResponse(['error' => $e->getMessage()], $e->getStatus()); } catch (\Exception $e) { return new DataResponse($e, Http::STATUS_CONFLICT); } - } /** @@ -116,6 +114,25 @@ public function createPersonalShare($token, $userName) { } } + /** + * SendInvitation + * Sent invitation mails for a share + * @NoAdminRequired + * @PublicPage + * @NoCSRFRequired + * @param string $token + * @return DataResponse + */ + public function sendInvitation($token) { + try { + $sentResult = $this->mailService->sendInvitationMail($token); + $share = $this->shareService->get($token); + return new DataResponse(['share' => $share, 'sentResult' => $sentResult], Http::STATUS_OK); + } catch (Exception $e) { + return new DataResponse(['error' => $e->getMessage()], $e->getStatus()); + } + } + /** * remove * remove share diff --git a/lib/Service/MailService.php b/lib/Service/MailService.php index d1a73c3ab..c0edc0856 100644 --- a/lib/Service/MailService.php +++ b/lib/Service/MailService.php @@ -155,8 +155,8 @@ private function getRecipientsByShare($share, $defaultLang = 'en', $skipUser = n $recipients[] = array( 'userId' => $share->getUserId(), - 'eMailAddress' => null, - 'displayName' => null, + 'eMailAddress' => \OC::$server->getConfig()->getUserValue($share->getUserId(), 'settings', 'email'), + 'displayName' => $this->userManager->get($share->getUserId())->getDisplayName(), 'language' => $this->config->getUserValue( $share->getUserId(), 'core', 'lang' @@ -229,9 +229,9 @@ private function getRecipientsByShare($share, $defaultLang = 'en', $skipUser = n $recipients[] = array( 'userId' => $member, - 'eMailAddress' => null, - 'displayName' => null, - 'language' => $this->config->getUserValue($share->getUserId(), 'core', 'lang'), + 'eMailAddress' => \OC::$server->getConfig()->getUserValue($member, 'settings', 'email'), + 'displayName' => $this->userManager->get($member)->getDisplayName(), + 'language' => $this->config->getUserValue($member, 'core', 'lang'), 'link' => $this->urlGenerator->getAbsoluteURL( $this->urlGenerator->linkToRoute( 'polls.page.indexvote', ['id' => $share->getPollId()] diff --git a/lib/Service/ShareService.php b/lib/Service/ShareService.php index bdc4177ce..5d8b47c4b 100644 --- a/lib/Service/ShareService.php +++ b/lib/Service/ShareService.php @@ -79,7 +79,6 @@ public function list($pollId) { } return $this->shareMapper->findByPoll($pollId); - } /** @@ -93,43 +92,6 @@ public function get($token) { return $this->shareMapper->findByToken($token); } - /** - * Write a new share to the db and returns the new share as array - * @NoAdminRequired - * @depricated - * @param int $pollId - * @param string $share - * @return array - */ - public function write($pollId, $type, $userId, $userEmail = '') { - - if (!$this->acl->setPollId($pollId)->getAllowEdit()) { - throw new NotAuthorizedException; - } - - $this->share = new Share(); - $this->share->setType($type); - $this->share->setPollId($pollId); - $this->share->setUserId($userId); - $this->share->setUserEmail($userEmail); - $this->share->setInvitationSent(0); - $this->share->setToken(\OC::$server->getSecureRandom()->generate( - 16, - ISecureRandom::CHAR_DIGITS . - ISecureRandom::CHAR_LOWER . - ISecureRandom::CHAR_UPPER - )); - - $this->share = $this->shareMapper->insert($this->share); - // TODO: Replace with $this->add and separate sending invitations - $sendResult = $this->mailService->sendInvitationMail($this->share->getToken()); - - return [ - 'share' => $this->share, - 'sendResult' => $sendResult - ]; - } - /** * Write a new share to the db and returns the new share as array * @NoAdminRequired @@ -157,7 +119,6 @@ public function add($pollId, $type, $userId, $userEmail = '') { )); return $this->shareMapper->insert($this->share); - } /** @@ -224,6 +185,5 @@ public function remove($token) { $this->shareMapper->delete($this->share); return $this->share; - } } From f1749a72e823a9a9d13dfe1f2390f71339a0a616 Mon Sep 17 00:00:00 2001 From: dartcafe Date: Sun, 5 Jul 2020 15:31:08 +0200 Subject: [PATCH 3/6] extend frontend for individual invitation sending --- img/mail.svg | 3 + package-lock.json | 14 ++++ package.json | 1 + src/img/mail.svg | 62 +++++++++++++++++ src/img/sendmail.svg | 68 +++++++++++++++++++ src/js/App.vue | 5 ++ src/js/components/SideBar/SideBarTabShare.vue | 57 ++++++++++++---- src/js/store/modules/subModules/shares.js | 59 ++++++++-------- 8 files changed, 228 insertions(+), 41 deletions(-) create mode 100644 img/mail.svg create mode 100644 src/img/mail.svg create mode 100644 src/img/sendmail.svg diff --git a/img/mail.svg b/img/mail.svg new file mode 100644 index 000000000..8cc90b436 --- /dev/null +++ b/img/mail.svg @@ -0,0 +1,3 @@ + + + diff --git a/package-lock.json b/package-lock.json index 839a62eb3..ba884cdb9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2875,6 +2875,15 @@ "core-js": "^3.6.4" } }, + "@nextcloud/dialogs": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@nextcloud/dialogs/-/dialogs-1.4.0.tgz", + "integrity": "sha512-Rx4x+al/sy+vXu2p3qvEuVeeUDm5JVwa84S21Hxa+pDV3Pd93E2dJGWlZ6h++5fSXbee1sDX9t957B20kYiP3Q==", + "requires": { + "core-js": "^3.6.4", + "toastify-js": "^1.7.0" + } + }, "@nextcloud/eslint-plugin": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/@nextcloud/eslint-plugin/-/eslint-plugin-1.4.0.tgz", @@ -11320,6 +11329,11 @@ "repeat-string": "^1.6.1" } }, + "toastify-js": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/toastify-js/-/toastify-js-1.8.0.tgz", + "integrity": "sha512-0Zf1sQ6Cs5RrRRDox00+6XdgS2tOtn01P9zhxDcJIpDS0KbXg/dFE1F0Mo6b/o63oJsxIhleeZv9LeZb31yKSg==" + }, "tough-cookie": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", diff --git a/package.json b/package.json index 4cae694e4..95336607f 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "dependencies": { "@nextcloud/auth": "^1.2.3", "@nextcloud/axios": "^1.3.1", + "@nextcloud/dialogs": "^1.4.0", "@nextcloud/event-bus": "^1.1.4", "@nextcloud/moment": "^1.1.1", "@nextcloud/router": "^1.0.0", diff --git a/src/img/mail.svg b/src/img/mail.svg new file mode 100644 index 000000000..0cfdbedcb --- /dev/null +++ b/src/img/mail.svg @@ -0,0 +1,62 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/src/img/sendmail.svg b/src/img/sendmail.svg new file mode 100644 index 000000000..6d99761e3 --- /dev/null +++ b/src/img/sendmail.svg @@ -0,0 +1,68 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/src/js/App.vue b/src/js/App.vue index 2e01d49af..6ce6cc6eb 100644 --- a/src/js/App.vue +++ b/src/js/App.vue @@ -120,6 +120,7 @@ export default { --icon-polls-maybe: url('/index.php/svg/polls/maybe-vote?color=ffc107&v=1'); --icon-polls: url('/index.php/svg/polls/app?color=000&v=1'); --icon-polls-handle: url('/index.php/svg/polls/handle?color=000&v=1'); + --icon-polls-mail: url('/index.php/svg/polls/mail?color=000&v=1'); // filters to colorize background svg from black // generated with https://codepen.io/jsm91/embed/ZEEawyZ?height=600&default-tab=result&embed-version=2 @@ -164,6 +165,10 @@ export default { background-image: var(--icon-polls-maybe); } +.icon-polls-mail { + background-image: var(--icon-polls-mail); +} + .title { margin: 8px 0; } diff --git a/src/js/components/SideBar/SideBarTabShare.vue b/src/js/components/SideBar/SideBarTabShare.vue index 095a1ecfd..b0ad9d8d8 100644 --- a/src/js/components/SideBar/SideBarTabShare.vue +++ b/src/js/components/SideBar/SideBarTabShare.vue @@ -24,13 +24,18 @@
- + + + {{ share.invitationSent ? t('polls', 'Resend invitation mail') : t('polls', 'Send invitation mail') }} + {{ t('polls', 'Copy link to clipboard') }} @@ -93,6 +98,23 @@ + + + + + + + {{ t('polls', 'Send invitation mail') }} + + + + +
@@ -103,6 +125,7 @@ import { mapState, mapGetters } from 'vuex' import { generateUrl } from '@nextcloud/router' import ConfigBox from '../Base/ConfigBox' import ButtonDiv from '../Base/ButtonDiv' +import { showSuccess, showError } from '@nextcloud/dialogs' export default { name: 'SideBarTabShare', @@ -138,11 +161,25 @@ export default { ...mapGetters({ invitationShares: 'poll/shares/invitation', + unsentInvitations: 'poll/shares/unsentInvitations', publicShares: 'poll/shares/public', }), }, methods: { + sendInvitation(share) { + this.$store.dispatch('poll/shares/sendInvitation', { share: share }) + .then((response) => { + response.data.sentResult.sentMails.forEach((item) => { + showSuccess(t('polls', 'Invitation sent to {name}', { name: item.displayName })) + }) + response.data.sentResult.abortedMails.forEach((item) => { + console.error('Mail could not be sent!', { recipient: item }) + showError(t('polls', 'Error sending invitation to {name}', { name: item.dispalyName })) + }) + }) + }, + loadUsersAsync(query) { this.isLoading = false this.siteUsersListOptions.query = query @@ -160,10 +197,10 @@ export default { this .$copyText(window.location.origin + payload.url) .then(() => { - OC.Notification.showTemporary(t('polls', 'Link copied to clipboard'), { type: 'success' }) + showSuccess(t('polls', 'Link copied to clipboard')) }) .catch(() => { - OC.Notification.showTemporary(t('polls', 'Error while copying link to clipboard'), { type: 'error' }) + showError(t('polls', 'Error while copying link to clipboard')) }) }, @@ -178,17 +215,13 @@ export default { addShare(payload) { this.$store .dispatch('poll/shares/add', { - share: { - type: payload.type, - userId: payload.user, - pollId: '0', - userEmail: payload.emailAddress, - token: '', - }, + type: payload.type, + userId: payload.user, + userEmail: payload.emailAddress, }) .catch(error => { console.error('Error while adding share - Error: ', error) - OC.Notification.showTemporary(t('polls', 'Error while adding share'), { type: 'error' }) + showError(t('polls', 'Error while adding share')) }) }, }, diff --git a/src/js/store/modules/subModules/shares.js b/src/js/store/modules/subModules/shares.js index e235b7f02..a8d3ce294 100644 --- a/src/js/store/modules/subModules/shares.js +++ b/src/js/store/modules/subModules/shares.js @@ -53,6 +53,11 @@ const mutations = { state.list.push(payload) }, + update(state, payload) { + const foundIndex = state.list.findIndex(share => share.id === payload.share.id) + Object.assign(state.list[foundIndex], payload.share) + }, + } const getters = { @@ -63,6 +68,12 @@ const getters = { }) }, + unsentInvitations: state => { + return state.list.filter(share => { + return share.userEmail && !share.invitationSent + }) + }, + public: state => { const invitationTypes = ['public'] return state.list.filter(share => { @@ -75,37 +86,14 @@ const getters = { const actions = { add(context, payload) { const endPoint = 'apps/polls/share/add' - payload.share.pollId = context.rootState.poll.id - return axios.post(generateUrl(endPoint), { pollId: context.rootState.poll.id, share: payload.share }) + return axios.post(generateUrl(endPoint), { + pollId: context.rootState.poll.id, + type: payload.type, + userId: payload.userId, + userEmail: payload.userEmail, + }) .then((response) => { context.commit('add', response.data.share) - - if (response.data.sendResult.sentMails.length > 0) { - const sendList = response.data.sendResult.sentMails.map(element => { - - if (element.displayName) { - return element.displayName - } else if (element.userId) { - return element.userId - } else if (element.eMailAddress) { - return element.eMailAddress - } - }) - OC.Notification.showTemporary(t('polls', 'Invitation mail sent to %n.', 1, sendList.join(', ')), { type: 'success' }) - } - - if (response.data.sendResult.abortedMails.length > 0) { - const errorList = response.data.sendResult.abortedMails.map(element => { - if (element.displayName) { - return element.displayName - } else if (element.userId) { - return element.userId - } else if (element.eMailAddress) { - return element.eMailAddress - } - }) - OC.Notification.showTemporary(t('polls', 'Error sending invitation mail to %n.', 1, errorList.join(', ')), { type: 'error' }) - } return response.data }) .catch((error) => { @@ -126,6 +114,19 @@ const actions = { }) }, + sendInvitation(context, payload) { + const endPoint = 'apps/polls/share/send' + return axios.post(generateUrl(endPoint.concat('/', payload.share.token))) + .then((response) => { + context.commit('update', { share: response.data.share }) + return response + }) + .catch((error) => { + console.error('Error sending invitation', { error: error.response }, { payload: payload }) + throw error + }) + }, + addPersonal(context, payload) { const endPoint = 'apps/polls/share/create/s' From 58f3acd75da4156222e0880be341a7c4ce385098 Mon Sep 17 00:00:00 2001 From: dartcafe Date: Sun, 5 Jul 2020 21:23:00 +0200 Subject: [PATCH 4/6] mark all invitations as sent while migrating --- lib/Migration/Version0105Date20200704084037.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/Migration/Version0105Date20200704084037.php b/lib/Migration/Version0105Date20200704084037.php index 6bdbf941b..934d2a59b 100644 --- a/lib/Migration/Version0105Date20200704084037.php +++ b/lib/Migration/Version0105Date20200704084037.php @@ -75,4 +75,16 @@ public function changeSchema(IOutput $output, \Closure $schemaClosure, array $op return $schema; } + /** + * @param IOutput $output + * @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @since 13.0.0 + */ + public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) { + $query = $this->connection->getQueryBuilder(); + $query->update('polls_share') + ->set('invitation_sent', 'id'); + $query->execute(); + } } From f60145b9286b611ad46d639e8b150e8acd74d8e5 Mon Sep 17 00:00:00 2001 From: dartcafe Date: Mon, 6 Jul 2020 09:06:16 +0200 Subject: [PATCH 5/6] adding groups to unsent invitations --- src/js/store/modules/subModules/shares.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/store/modules/subModules/shares.js b/src/js/store/modules/subModules/shares.js index a8d3ce294..633293026 100644 --- a/src/js/store/modules/subModules/shares.js +++ b/src/js/store/modules/subModules/shares.js @@ -70,7 +70,7 @@ const getters = { unsentInvitations: state => { return state.list.filter(share => { - return share.userEmail && !share.invitationSent + return (share.userEmail || share.type === 'group') && !share.invitationSent }) }, From 0a1a63adbdf04ab0efb6bde2b344c43817aabc44 Mon Sep 17 00:00:00 2001 From: dartcafe Date: Mon, 6 Jul 2020 09:29:30 +0200 Subject: [PATCH 6/6] removed scr/img --- src/img/mail.svg | 62 ---------------------------------------- src/img/sendmail.svg | 68 -------------------------------------------- 2 files changed, 130 deletions(-) delete mode 100644 src/img/mail.svg delete mode 100644 src/img/sendmail.svg diff --git a/src/img/mail.svg b/src/img/mail.svg deleted file mode 100644 index 0cfdbedcb..000000000 --- a/src/img/mail.svg +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - diff --git a/src/img/sendmail.svg b/src/img/sendmail.svg deleted file mode 100644 index 6d99761e3..000000000 --- a/src/img/sendmail.svg +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - -