diff --git a/apps/files_sharing/css/sharetabview.css b/apps/files_sharing/css/sharetabview.css
index bd39bb9b55f8..2a2655347d44 100644
--- a/apps/files_sharing/css/sharetabview.css
+++ b/apps/files_sharing/css/sharetabview.css
@@ -1,292 +1,298 @@
.app-files .shareTabView {
- min-height: 100px;
+ min-height: 100px;
}
.shareTabView .oneline {
- white-space: nowrap;
+ white-space: nowrap;
}
.shareTabView .shareWithLoading {
- padding-left: 10px;
- right: 30px;
- top: 2px;
+ padding-left: 10px;
+ right : 30px;
+ top : 2px;
}
.shareTabView label {
- white-space: nowrap;
+ white-space: nowrap;
}
.shareTabView input[type="checkbox"] {
- margin: 0 3px 0 8px;
- vertical-align: middle;
+ margin : 0 3px 0 8px;
+ vertical-align: middle;
}
.shareTabView input[type="text"],
.shareTabView input[type="password"] {
- width: 94%;
- margin-left: 0;
+ width : 94%;
+ margin-left: 0;
}
.shareTabView input[type="text"].shareWithField,
.shareTabView input[type="text"].emailField,
.shareTabView input[type="text"].linkText {
- width: 80%;
+ width: 80%;
}
.shareTabView form {
- font-size: 100%;
- margin-left: 0;
- margin-right: 0;
+ font-size : 100%;
+ margin-left : 0;
+ margin-right: 0;
}
#shareWithList {
- list-style-type: none;
- padding: 0 0 16px;
+ list-style-type: none;
+ padding : 0 0 16px;
}
#shareWithList li {
- padding-top: 5px;
- padding-bottom: 5px;
- font-weight: bold;
- white-space: normal;
+ padding-top : 5px;
+ padding-bottom: 5px;
+ font-weight : bold;
+ white-space : normal;
}
-#shareWithList .unshare img,
-#shareWithList .showCruds img {
- vertical-align: text-bottom;
- /* properly align icons */
+#shareWithList .showCruds img,
+#shareWithList .unshare img {
+ vertical-align: text-bottom;
+ /* properly align icons */
}
#shareWithList label input[type=checkbox] {
- margin-left: 0;
- position: relative;
+ margin-left: 0;
+ position : relative;
}
#shareWithList .username {
- padding-right: 8px;
- white-space: nowrap;
- text-overflow: ellipsis;
- max-width: 254px;
- display: inline-block;
- overflow: hidden;
- vertical-align: middle;
+ padding-right : 8px;
+ white-space : nowrap;
+ text-overflow : ellipsis;
+ max-width : 254px;
+ display : inline-block;
+ overflow : hidden;
+ vertical-align: middle;
}
#shareWithList li label {
- margin-right: 8px;
+ margin-right: 8px;
}
.shareTabView .icon-loading-small {
- display: inline-block;
- z-index: 1;
- background-color: white;
- padding: 2px 0;
+ display : inline-block;
+ z-index : 1;
+ background-color: white;
+ padding : 2px 0;
}
-.shareTabView .shareWithList .icon-loading-small,
-.shareTabView .linkShareView .icon-loading-small {
- position: absolute;
+.shareTabView .linkShareView .icon-loading-small,
+.shareTabView .shareWithList .icon-loading-small {
+ position: absolute;
}
.shareTabView .linkPass .icon-loading-small {
- margin-top: 9px;
+ margin-top: 9px;
}
.shareTabView .icon {
- display: inline-block;
- background-size: 16px 16px;
+ display : inline-block;
+ background-size: 16px 16px;
}
.shareTabView .privacyWarningMessage {
- margin-top: 20px;
+ margin-top: 20px;
}
.shareTabView .shareWithList .mailNotificationSpinner {
- position: relative;
- vertical-align: middle;
- margin-right: 10px;
+ position : relative;
+ vertical-align: middle;
+ margin-right : 10px;
}
.subTabHeaders .tabHeaders {
- margin-left: 0px;
- margin-right: 0px;
+ margin-left : 0;
+ margin-right: 0;
}
.link-shares {
- margin-bottom: 20px;
+ margin-bottom: 20px;
}
.link-entry {
- display: flex;
- align-items: center;
- min-height: 50px;
- position: relative;
+ display : flex;
+ align-items: center;
+ min-height : 50px;
+ position : relative;
}
.link-entry:not(:last-child) {
- border-bottom: 1px solid #eee;
+ border-bottom: 1px solid #eee;
}
.link-entry .socialShareContainer {
- position: absolute;
- right: 0;
- top: -20px;
- background-color: rgba(0, 0, 0, 0.5);
- padding: 0 2px 2px 5px;
- border-radius: 3px;
+ position : absolute;
+ right : 0;
+ top : -20px;
+ background-color: rgba(0, 0, 0, 0.5);
+ padding : 0 2px 2px 5px;
+ border-radius : 3px;
}
.link-entry--icon {
- height: 32px;
- width: 32px;
- background-color: #b4b4b4;
- background-position: 8px 8px;
- border-radius: 50%;
- margin-right: 10px;
- flex-shrink: 0;
+ height : 32px;
+ width : 32px;
+ background-color : #b4b4b4;
+ background-position: 8px 8px;
+ border-radius : 50%;
+ margin-right : 10px;
}
.link-entry--title {
- flex-grow: 1;
- font-weight: bold;
+ flex-grow : 1;
+ font-weight: bold;
}
.link-entry--icon-button {
- margin-left: 5px;
- opacity: .333;
- -webkit-transition: opacity .25s;
- -moz-transition: opacity .25s;
- -ms-transition: opacity .25s;
- -o-transition: opacity .25s;
- transition: opacity .25s;
+ margin-left : 5px;
+ opacity : 0.333;
+ -webkit-transition: opacity 0.25s;
+ -moz-transition : opacity 0.25s;
+ -ms-transition : opacity 0.25s;
+ -o-transition : opacity 0.25s;
+ transition : opacity 0.25s;
}
.link-entry--icon-button:hover {
- opacity: 1;
+ opacity: 1;
}
.link-entry--icon-button span {
- cursor: pointer;
+ cursor: pointer;
}
/* -------------------------------------------------- USER & GROUP SHARES --- */
.user-shares {
- margin: 20px -15px;
+ margin: 20px -15px;
}
.user-share {
- transition: all 0.25s ease;
- padding: 0 15px;
+ transition: all 0.25s ease;
+ padding : 0 15px;
}
.user-share .icon-settings-dark {
- transition: all 0.25s ease;
- opacity: .25;
+ transition: all 0.25s ease;
+ opacity : 0.25;
}
.user-share.-active,
.user-share:hover {
- background-color: #eee;
+ background-color: #eee;
}
.user-share.-active .icon-settings-dark,
.user-share:hover .icon-settings-dark {
- opacity: .25;
+ opacity: 0.25;
}
.user-share.-active .user-share--dropdown {
- height: 30px;
+ height: 30px;
}
.user-share:not(:last-child) {
- border-bottom: 1px solid #eee;
+ border-bottom: 1px solid #eee;
}
.user-share .icon-settings-dark {
- opacity: 0;
+ opacity: 0;
}
.user-share--user {
- display: flex;
- align-items: center;
+ display : flex;
+ align-items: center;
}
.user-share--title {
- font-weight: bold;
- margin-right: 5px;
+ font-weight : bold;
+ margin-right: 5px;
}
.user-share--main {
- display: flex;
- align-items: center;
- min-height: 50px;
- justify-content: space-between;
+ display : flex;
+ align-items : center;
+ min-height : 50px;
+ justify-content: space-between;
}
.user-share--checkbox:not(:first-child) {
- margin-left: 5px;
+ margin-left: 5px;
}
.user-share--dropdown {
- overflow: hidden;
- height: 0;
- transition: height 0.25s ease-in-out;
- display: flex;
- justify-content: space-between;
+ overflow : hidden;
+ height : 0;
+ transition : height 0.25s ease-in-out;
+ display : flex;
+ justify-content: space-between;
}
.user-share--permission-preview {
- white-space: nowrap;
- overflow: hidden;
- -ms-text-overflow: ellipsis;
- text-overflow: ellipsis;
+ white-space : nowrap;
+ overflow : hidden;
+ -ms-text-overflow: ellipsis;
+ text-overflow : ellipsis;
}
.user-share--permission-preview li {
- display: inline;
- font-size: 12px;
+ display : inline;
+ font-size: 12px;
}
.user-share--permission-preview li:first-child:before {
- content: '(';
+ content: "(";
}
.user-share--permission-preview li:not(:last-child):after {
- content: ',';
+ content: ",";
}
.user-share--permission-preview li:last-child:after {
- content: ')';
+ content: ")";
}
.user-share--permission-list li {
- display: inline;
+ display: inline;
}
.user-share--toggle-dropdown {
- cursor: pointer;
+ cursor: pointer;
}
/* ---------------------------------------------------- PUBLIC LINK MODAL --- */
.public-link-modal--item {
- margin-bottom: 20px;
+ margin-bottom: 20px;
}
-.public-link-modal--label,
-.public-link-modal--input {
- display: block;
- width: calc(100% - 15px) !important;
+.public-link-modal--input,
+.public-link-modal--label {
+ position: relative;
+ display : block;
+ width : calc(100% - 15px) !important;
+}
+
+.public-link-modal--input[type="password"],
+.public-link-modal--input.datepicker {
+ max-width: 50%;
+ min-width: 175px;
}
.minify {
- width: 1px;
- height: 1px;
- overflow: hidden;
- opacity: 0;
+ width : 1px;
+ height : 1px;
+ overflow: hidden;
+ opacity : 0;
}
.minify input {
- font-size: 1px;
+ font-size: 1px;
}
diff --git a/apps/files_versions/tests/js/versionmodelSpec.js b/apps/files_versions/tests/js/versionmodelSpec.js
index 2380a439e9de..20fbe1a719e5 100644
--- a/apps/files_versions/tests/js/versionmodelSpec.js
+++ b/apps/files_versions/tests/js/versionmodelSpec.js
@@ -15,6 +15,7 @@ describe('OCA.Versions.VersionModel', function() {
var requestStub;
var requestDeferred;
+ var currentUserStub;
beforeEach(function() {
model = new VersionModel({
@@ -25,12 +26,13 @@ describe('OCA.Versions.VersionModel', function() {
name: 'some file.txt',
size: 150,
});
- OC.currentUser = 'user0';
+ currentUserStub = sinon.stub(OC, 'getCurrentUser').returns({uid: 'user0'});
requestDeferred = new $.Deferred();
requestStub = sinon.stub(dav.Client.prototype, 'request').returns(requestDeferred.promise());
});
afterEach(function() {
+ currentUserStub.restore();
requestStub.restore();
});
diff --git a/core/ajax/share.php b/core/ajax/share.php
index 366136974d4c..7b6c3fe289ae 100644
--- a/core/ajax/share.php
+++ b/core/ajax/share.php
@@ -130,6 +130,7 @@ function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
$defaults,
\OC::$server->getURLGenerator()
);
+
$result = $mailNotification->sendInternalShareMail($recipientList, $itemSource, $itemType);
// if we were able to send to at least one recipient, mark as sent
@@ -143,7 +144,7 @@ function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
} else {
OCP\JSON::error([
'data' => [
- 'message' => $l->t("Couldn't send mail to following users: %s ",
+ 'message' => $l->t("Couldn't send mail to following recipient(s): %s ",
implode(', ', $result)
)
]
@@ -160,6 +161,7 @@ function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
break;
case 'email':
+
// read and filter post variables
$filter = new MailNotificationFilter([
'link' => $_POST['link'],
@@ -168,9 +170,26 @@ function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
'expiration' => $_POST['expiration']
]);
+ // read post variables
+ $link = (string)$_POST['link'];
+ $file = (string)$_POST['file'];
+ $toAddress = (string)$_POST['toAddress'];
+ $options = array();
+ $emailBody = null;
+
+ if (isset($_POST['emailBody'])) {
+ $emailBody = trim((string)$_POST['emailBody']);
+ }
+
+ if (isset($_POST['bccSelf']) && $_POST['bccSelf'] === 'true') {
+ $options['bcc'] = \OC::$server->getUserSession()->getUser()->getEMailAddress();
+ }
+
+ $l10n = \OC::$server->getL10N('lib');
+
$mailNotification = new \OC\Share\MailNotifications(
\OC::$server->getUserSession()->getUser(),
- \OC::$server->getL10N('lib'),
+ $l10n,
\OC::$server->getMailer(),
\OC::$server->getLogger(),
$defaults,
@@ -191,6 +210,16 @@ function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
$filter->getToAddress(), $filter->getFile(), $filter->getLink(), $expiration
);
+ $subject = (string)$l10n->t('%s shared »%s« with you', [$this->senderDisplayName, $filename]);
+ if ($emailBody === null || $emailBody === '') {
+ list($htmlBody, $textBody) = $mailNotification->createMailBody($file, $link, $expiration);
+ } else {
+ $htmlBody = null;
+ $textBody = strip_tags($emailBody);
+ }
+
+ $result = $mailNotification->sendLinkShareMailFromBody($toAddress, $subject, $htmlBody, $textBody, $options);
+
if(empty($result)) {
// Get the token from the link
$linkParts = explode('/', $link);
@@ -217,7 +246,7 @@ function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
->setAuthor($currentUser)
->setAffectedUser($currentUser)
->setObject('files', $fileId, $path)
- ->setSubject(\OCA\Files_Sharing\Activity::SUBJECT_SHARED_EMAIL, [$path, $to_address]);
+ ->setSubject(\OCA\Files_Sharing\Activity::SUBJECT_SHARED_EMAIL, [$path, $toAddress]);
\OC::$server->getActivityManager()->publish($event);
}
}
@@ -228,7 +257,7 @@ function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
$l = \OC::$server->getL10N('core');
OCP\JSON::error([
'data' => [
- 'message' => $l->t("Couldn't send mail to following users: %s ",
+ 'message' => $l->t("Couldn't send mail to following recipient(s): %s ",
implode(', ', $result)
)
]
@@ -323,12 +352,12 @@ function usersInGroup($gid, $search = '', $limit = -1, $offset = 0) {
$sharedGroups = [];
if (isset($_GET['itemShares'])) {
if (isset($_GET['itemShares'][OCP\Share::SHARE_TYPE_USER]) &&
- is_array($_GET['itemShares'][OCP\Share::SHARE_TYPE_USER])) {
+ is_array($_GET['itemShares'][OCP\Share::SHARE_TYPE_USER])) {
$sharedUsers = $_GET['itemShares'][OCP\Share::SHARE_TYPE_USER];
}
if (isset($_GET['itemShares'][OCP\Share::SHARE_TYPE_GROUP]) &&
- is_array($_GET['itemShares'][OCP\Share::SHARE_TYPE_GROUP])) {
+ is_array($_GET['itemShares'][OCP\Share::SHARE_TYPE_GROUP])) {
$sharedGroups = $_GET['itemShares'][OCP\Share::SHARE_TYPE_GROUP];
}
}
diff --git a/core/css/global.css b/core/css/global.css
index 9511d4324fa4..f2408944b320 100644
--- a/core/css/global.css
+++ b/core/css/global.css
@@ -4,6 +4,15 @@
/* Global Components */
+/* Positioning */
+
+.absolute-center {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+}
+
.pull-left {
float: left;
}
@@ -24,7 +33,7 @@
clear: both;
}
-.hidden {
+.hidden.hidden {
display: none;
}
@@ -41,10 +50,25 @@
font-weight:600;
}
-.center {
- text-align:center;
+.text-small {
+ font-size: 80%;
}
.inlineblock {
display: inline-block;
-}
\ No newline at end of file
+}
+
+/* Text */
+
+.text-right {
+ text-align: right;
+}
+
+.center,
+.text-center {
+ text-align: center;
+}
+
+.text-left {
+ text-align: left;
+}
diff --git a/core/css/jquery.ocdialog.css b/core/css/jquery.ocdialog.css
index 4c789965a6dc..e170ef4bd099 100644
--- a/core/css/jquery.ocdialog.css
+++ b/core/css/jquery.ocdialog.css
@@ -91,29 +91,11 @@
height : 100%;
}
-.error-message-global {
+.error-message-global,
+.success-message-global {
background-color : rgb(242, 222, 222);
- border-bottom-color : rgb(235, 204, 209);
- border-bottom-left-radius : 4px;
- border-bottom-right-radius: 4px;
- border-bottom-style : solid;
- border-bottom-width : 1px;
- border-image-outset : 0 0 0 0;
- border-image-repeat : stretch stretch;
- border-image-slice : 100% 100% 100% 100%;
- border-image-source : none;
- border-image-width : 1 1 1 1;
- border-left-color : rgb(235, 204, 209);
- border-left-style : solid;
- border-left-width : 1px;
- border-right-color : rgb(235, 204, 209);
- border-right-style : solid;
- border-right-width : 1px;
- border-top-color : rgb(235, 204, 209);
- border-top-left-radius : 4px;
- border-top-right-radius : 4px;
- border-top-style : solid;
- border-top-width : 1px;
+ border : 1px solid rgb(235, 204, 209);
+ border-radius : 4px;
box-sizing : border-box;
color : rgb(169, 68, 66);
font-family : Verdana,sans-serif;
@@ -130,5 +112,10 @@
-moz-border-left-colors : none;
-moz-border-right-colors : none;
-moz-border-top-colors : none;
+}
+.success-message-global {
+ background-color: rgb(222, 242, 226);
+ border-color : rgb(177, 218, 186);
+ color : rgb(66, 169, 76);
}
diff --git a/core/css/share.css b/core/css/share.css
index 5dd8e10c68ac..76eabdbcef61 100644
--- a/core/css/share.css
+++ b/core/css/share.css
@@ -209,3 +209,23 @@ a.showCruds:hover,a.unshare:hover {
padding-top: 12px;
color: #999;
}
+
+/* Private Link share Form */
+
+.emailPrivateLinkForm {
+ position: relative;
+}
+
+.emailPrivateLinkForm--send-indicator {
+ z-index: 2;
+ /* overriding default padding */
+ padding: 5px 15px !important;
+}
+
+.emailPrivateLinkForm--addAddressButton {
+ position: absolute;
+ right: 13px;
+ margin-top: -30px;
+ z-index: 1;
+ color: #999;
+}
diff --git a/core/js/config.php b/core/js/config.php
index 279aa4668067..f7c574ddf392 100644
--- a/core/js/config.php
+++ b/core/js/config.php
@@ -207,6 +207,15 @@
// remove status.php info as we already have the version above
unset($caps['core']['status']);
$array['oc_capabilities'] = json_encode($caps);
+
+ $user = \OC::$server->getUserSession()->getUser();
+ if ($user !== null) {
+ $array['oc_user'] = json_encode([
+ 'uid' => $user->getUID(),
+ 'displayName' => $user->getDisplayName(),
+ 'email' => $user->getEMailAddress()
+ ]);
+ }
}
// Allow hooks to modify the output values
diff --git a/core/js/js.js b/core/js/js.js
index f0c7c19ae270..1d2c68811c55 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -11,7 +11,6 @@
var oc_debug;
var oc_webroot;
-var oc_current_user = document.getElementsByTagName('head')[0].getAttribute('data-user');
var oc_requesttoken = document.getElementsByTagName('head')[0].getAttribute('data-requesttoken');
window.oc_config = window.oc_config || {};
@@ -82,7 +81,7 @@ var OC = {
* @type String
* @deprecated use {@link OC.getCurrentUser} instead
*/
- currentUser: (typeof oc_current_user !== 'undefined') ? oc_current_user : false,
+ currentUser: (typeof oc_user !== 'undefined') ? oc_user.uid : false,
config: window.oc_config,
appConfig: window.oc_appconfig || {},
theme: window.oc_defaults || {},
@@ -322,12 +321,13 @@ var OC = {
* @since 9.0.0
*/
getCurrentUser: function () {
- if (_.isUndefined(this._currentUserDisplayName)) {
- this._currentUserDisplayName = document.getElementsByTagName('head')[0].getAttribute('data-user-displayname');
+ if (!_.isUndefined(window.oc_user)) {
+ return oc_user;
}
return {
- uid: this.currentUser,
- displayName: this._currentUserDisplayName
+ uid: null,
+ displayName: null,
+ email: null
};
},
diff --git a/core/js/sharedialogexpirationview.js b/core/js/sharedialogexpirationview.js
index f10d22a49c05..b76110dc6bdd 100644
--- a/core/js/sharedialogexpirationview.js
+++ b/core/js/sharedialogexpirationview.js
@@ -113,7 +113,7 @@
cid: this.cid,
setExpirationLabel: t('core', 'Set expiration date'),
expirationLabel: t('core', 'Expiration'),
- expirationDatePlaceholder: t('core', 'Expiration date'),
+ expirationDatePlaceholder: t('core', 'Choose an expiration date'),
defaultExpireMessage: defaultExpireMessage,
isExpirationSet: isExpirationSet,
isExpirationEnforced: isExpirationEnforced,
diff --git a/core/js/sharedialoglinkshareview.js b/core/js/sharedialoglinkshareview.js
index 6211b2dec477..fb249fc7e88e 100644
--- a/core/js/sharedialoglinkshareview.js
+++ b/core/js/sharedialoglinkshareview.js
@@ -14,7 +14,7 @@
}
var PASSWORD_PLACEHOLDER_STARS = '**********';
- var PASSWORD_PLACEHOLDER_MESSAGE = t('core', 'Choose a password for the public link');
+ var PASSWORD_PLACEHOLDER_MESSAGE = t('core', 'Choose a password');
var TEMPLATE =
'
' +
''+
@@ -194,11 +194,8 @@
success: function() {
if (self.mailView) {
// also send out email first
- self.mailView.sendEmails().then(done).fail(function() {
- done();
- // re-show the popup
- self.show();
- });
+ // do not resolve on errors
+ self.mailView.sendEmails().then(done);
} else {
done();
}
@@ -243,7 +240,7 @@
publicUploadPossible : this._isPublicUploadPossible(),
- publicUploadLabel : t('core', 'Upload only (File Drop)'),
+ publicUploadLabel : t('core', 'Upload only') + ' (File Drop)',
publicUploadDescription : t('core', 'Receive files from others without revealing the contents of the folder.'),
publicUploadValue : OC.PERMISSION_CREATE,
publicUploadSelected : this.model.get('permissions') === OC.PERMISSION_CREATE,
@@ -326,18 +323,27 @@
var self = this;
var title = t('files_sharing', 'Edit link share: {name}', {name: this.itemModel.getFileInfo().getFullPath()});
var buttons = [{
- text: t('core', 'Save'),
- click: _.bind(this._onClickSave, this),
- defaultButton: true
- }, {
text: t('core', 'Cancel'),
click: _.bind(this._onClickCancel, this)
}];
if (this.model.isNew()) {
title = t('files_sharing', 'Create link share: {name}', {name: this.itemModel.getFileInfo().getFullPath()});
+ buttons.unshift({
+ text: t('core', 'Share'),
+ click: _.bind(this._onClickSave, this),
+ defaultButton: true
+ })
}
- else if (this.model.get('encryptedPassword')) {
+ else {
+ buttons.unshift({
+ text: t('core', 'Save'),
+ click: _.bind(this._onClickSave, this),
+ defaultButton: true
+ })
+ }
+
+ if (this.model.get('encryptedPassword')) {
buttons.push({
classes: 'removePassword -float-left',
text: t('core', 'Remove password'),
diff --git a/core/js/sharedialogmailview.js b/core/js/sharedialogmailview.js
index 35635c60e748..042e75013743 100644
--- a/core/js/sharedialogmailview.js
+++ b/core/js/sharedialogmailview.js
@@ -12,14 +12,23 @@
if (!OC.Share) {
OC.Share = {};
}
-
- var TEMPLATE =
- '
'
- ;
-
+
+ var TEMPLATE =
+ '
';
+
/**
* @class OCA.Share.ShareDialogMailView
* @member {OC.Share.ShareItemModel} model
@@ -34,121 +43,131 @@
/** @type {string} **/
id: 'shareDialogMailView',
+ events: {
+ "keyup .emailPrivateLinkForm--emailField" : "toggleMailElements",
+ "keydown .emailPrivateLinkForm--emailBodyField" : "expandMailBody"
+ },
+
/** @type {Function} **/
_template: undefined,
initialize: function(options) {
- if(!_.isUndefined(options.itemModel)) {
+ if (!_.isUndefined(options.itemModel)) {
this.itemModel = options.itemModel;
} else {
throw 'missing OC.Share.ShareItemModel';
}
},
+ toggleMailElements: function() {
+ var $email = this.$el.find('.emailPrivateLinkForm--emailField');
+ var $emailElements = this.$el.find('.emailPrivateLinkForm--elements');
+
+ if ($email.val().length > 0 && $emailElements.is(":hidden")) {
+ $emailElements.slideDown();
+ } else if ($email.val().length === 0 && $emailElements.is(":visible")) {
+ $emailElements.slideUp();
+ }
+ },
+
+ expandMailBody: function(event) {
+ var $emailBody = this.$el.find('.emailPrivateLinkForm--emailBodyField');
+ $emailBody.css('minHeight', $emailBody[0].scrollHeight - 12);
+
+ if (event.keyCode == 13) {
+ event.stopPropagation();
+ }
+ },
+
/**
* Send the link share information by email
*
* @param {string} recipientEmail recipient email address
*/
- _sendEmailPrivateLink: function(recipientEmail) {
- var deferred = $.Deferred();
- var itemType = this.itemModel.get('itemType');
+ _sendEmailPrivateLink: function(mail) {
+ var deferred = $.Deferred();
+ var itemType = this.itemModel.get('itemType');
var itemSource = this.itemModel.get('itemSource');
- if (!this.validateEmail(recipientEmail)) {
- deferred.reject();
+ if (!this.validateEmail(mail.to)) {
+ return deferred.reject({
+ message: t('core', '{email} is not a valid address!', {email: mail.to})
+ });
}
+ var params = {
+ action : 'email',
+ toAddress : mail.to,
+ emailBody : mail.body,
+ bccSelf : mail.bccSelf,
+ link : this.model.getLink(),
+ itemType : itemType,
+ itemSource : itemSource,
+ file : this.itemModel.getFileInfo().get('name'),
+ expiration : this.model.get('expireDate') || ''
+ };
+
$.post(
- OC.generateUrl('core/ajax/share.php'), {
- action: 'email',
- toaddress: recipientEmail,
- link: this.model.getLink(),
- itemType: itemType,
- itemSource: itemSource,
- file: this.itemModel.getFileInfo().get('name'),
- expiration: this.model.get('expireDate') || ''
- },
+ OC.generateUrl('core/ajax/share.php'), params,
function(result) {
if (!result || result.status !== 'success') {
- OC.dialogs.alert(result.data.message, t('core', 'Error while sending notification'));
- deferred.reject();
+ deferred.reject({
+ message: result.data.message
+ });
} else {
deferred.resolve();
}
- }).fail(function() {
- deferred.reject();
+ }).fail(function(error) {
+ return deferred.reject();
});
return deferred.promise();
},
- validateEmail: function (email) {
+ validateEmail: function(email) {
+ if (email.length === 0)
+ return true
+
return email.match(/([\w\.\-_]+)?\w+@[\w-_]+(\.\w+){1,}$/);
},
sendEmails: function() {
- var $emailField = this.$el.find('.emailField');
- var $emailButton = this.$el.find('.emailButton');
- var email = $emailField.val();
- if (email !== '') {
- $emailField.prop('disabled', true);
- $emailButton.prop('disabled', true);
- $emailField.val(t('core', 'Sending ...'));
- return this._sendEmailPrivateLink(email).done(function() {
- $emailField.css('font-weight', 'bold').val(t('core','Email sent'));
+ var $formItems = this.$el.find('.emailPrivateLinkForm input, .emailPrivateLinkForm textarea');
+ var $formSendIndicator = this.$el.find('.emailPrivateLinkForm--send-indicator');
+ var mail = {
+ to : this.$el.find('.emailPrivateLinkForm--emailField').val().toLowerCase(),
+ bccSelf : this.$el.find('.emailPrivateLinkForm--emailBccSelf').is(':checked'),
+ body : this.$el.find('.emailPrivateLinkForm--emailBodyField').val()
+ };
+
+ if (mail.to !== '') {
+ $formItems.prop('disabled', true);
+ $formSendIndicator.removeClass('hidden');
+ return this._sendEmailPrivateLink(mail).done(function() {
setTimeout(function() {
- $emailField.val('');
- $emailField.css('font-weight', 'normal');
- $emailField.prop('disabled', false);
- $emailButton.prop('disabled', false);
+ $formItems.prop('disabled', false);
+ $formSendIndicator.addClass('hidden');
}, 2000);
- }).fail(function() {
- $emailField.val(email);
- $emailField.css('font-weight', 'normal');
- $emailField.prop('disabled', false);
- $emailButton.prop('disabled', false);
+ }).fail(function(error) {
+ OC.dialogs.info(error.message, t('core', 'An error occured'));
+ $formSendIndicator.addClass('hidden');
+ $formItems.prop('disabled', false);
});
}
return $.Deferred().resolve();
},
render: function() {
- var email = this.$el.find('.emailField').val();
-
this.$el.html(this.template({
- cid: this.cid,
- mailPrivatePlaceholder: t('core', 'Email link to person'),
- mailLabel: t('core', 'Send link via email'),
- email: email
+ cid : this.cid,
+ userHasEmail : !!OC.getCurrentUser().email,
+ mailPlaceholder : t('core', 'Email link to person'),
+ bccSelf : t('core', 'Send copy to self'),
+ mailLabel : t('core', 'Send link via email'),
+ mailBodyPlaceholder : t('core', 'Add personal message'),
+ sending : t('core', 'Sending') + ' ...'
}));
- var $emailField = this.$el.find('.emailField');
- if ($emailField.length !== 0) {
- $emailField.autocomplete({
- minLength: 1,
- source: function (search, response) {
- $.get(
- OC.generateUrl('core/ajax/share.php'), {
- fetch: 'getShareWithEmail',
- search: search.term
- }, function(result) {
- if (result.status == 'success' && result.data.length > 0) {
- response(result.data);
- }
- });
- },
- select: function( event, item ) {
- $emailField.val(item.item.email);
- return false;
- }
- })
- .data("ui-autocomplete")._renderItem = function( ul, item ) {
- return $('
')
- .append('' + escapeHTML(item.displayname) + "
" + escapeHTML(item.email) + '' )
- .appendTo( ul );
- };
- }
this.delegateEvents();
return this;
diff --git a/core/js/tests/specs/sharedialoglinkshareviewSpec.js b/core/js/tests/specs/sharedialoglinkshareviewSpec.js
index 7c44a3525672..2ecdbca648ff 100644
--- a/core/js/tests/specs/sharedialoglinkshareviewSpec.js
+++ b/core/js/tests/specs/sharedialoglinkshareviewSpec.js
@@ -28,7 +28,7 @@ describe('OC.Share.ShareDialogLinkShareView', function() {
var view;
var PASSWORD_PLACEHOLDER_STARS = '**********';
- var PASSWORD_PLACEHOLDER_MESSAGE = 'Choose a password for the public link';
+ var PASSWORD_PLACEHOLDER_MESSAGE = 'Choose a password';
beforeEach(function() {
configModel = new OC.Share.ShareConfigModel();
diff --git a/core/js/tests/specs/sharedialogmailviewSpec.js b/core/js/tests/specs/sharedialogmailviewSpec.js
index 599780d2ff81..355a54cd20b5 100644
--- a/core/js/tests/specs/sharedialogmailviewSpec.js
+++ b/core/js/tests/specs/sharedialogmailviewSpec.js
@@ -1,23 +1,23 @@
/**
-* ownCloud
-*
-* @author Vincent Petry
-* @copyright Copyright (c) 2017 Vincent Petry
-*
-* This library is free software; you can redistribute it and/or
-* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
-* License as published by the Free Software Foundation; either
-* version 3 of the License, or any later version.
-*
-* This library 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 library. If not, see .
-*
-*/
+ * ownCloud
+ *
+ * @author Vincent Petry
+ * @copyright Copyright (c) 2017 Vincent Petry
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library 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 library. If not, see .
+ *
+ */
/* global oc_appconfig */
describe('OC.Share.ShareDialogMailView', function() {
@@ -25,7 +25,7 @@ describe('OC.Share.ShareDialogMailView', function() {
var view;
var model;
var itemModel;
- var autocompleteStub;
+ var currentUserStub;
beforeEach(function() {
var configModel = new OC.Share.ShareConfigModel();
@@ -47,9 +47,10 @@ describe('OC.Share.ShareDialogMailView', function() {
fileInfoModel: fileInfoModel
});
- autocompleteStub = sinon.stub($.fn, 'autocomplete').callsFake(function() {
- $(this).data('ui-autocomplete', {});
- return $(this);
+ currentUserStub = sinon.stub(OC, 'getCurrentUser').returns({
+ uid: 'someuser',
+ displayName: 'Some User',
+ email: 'someuser@example.org'
});
model = new OC.Share.ShareModel({
@@ -70,34 +71,45 @@ describe('OC.Share.ShareDialogMailView', function() {
});
view.render();
});
-
- afterEach(function() {
- view.remove();
- autocompleteStub.restore();
- });
- it('rendering', function() {
- expect(view.$('.emailField').length).toEqual(1);
+ afterEach(function() {
+ view.remove();
+ currentUserStub.restore();
});
- describe('autocomplete', function() {
-
- it('asks the server for matching email addresses', function() {
- expect(autocompleteStub.calledOnce).toEqual(true);
+ describe('renders', function() {
+ it('bcc checkbox field if usermail is present', function() {
+ // mail set in initial currentUserStub
+ expect(view.$('.emailPrivateLinkForm--emailBccSelf').length).toEqual(1);
+ });
+ });
+ describe('sending emails', function() {
+ it('sends entered emails when calling sendEmails()', function() {
var callback = sinon.stub();
- autocompleteStub.getCall(0).args[0].source({
- term: 'search@example.com'
- }, callback);
+ view.$('.emailPrivateLinkForm--emailField').val('email@example.com');
+ view.sendEmails().then(callback);
+ expect(callback.notCalled).toEqual(true);
expect(fakeServer.requests.length).toEqual(1);
-
- expect(fakeServer.requests[0].method).toEqual('GET');
- expect(fakeServer.requests[0].url).toEqual(OC.generateUrl('core/ajax/share.php') + '?fetch=getShareWithEmail&search=search%40example.com');
+ expect(fakeServer.requests[0].method).toEqual('POST');
+ expect(fakeServer.requests[0].url).toEqual(OC.generateUrl('core/ajax/share.php'));
+ expect(OC.parseQueryString(fakeServer.requests[0].requestBody)).toEqual({
+ action: 'email',
+ toAddress: 'email@example.com',
+ link: model.getLink(),
+ itemType: 'folder',
+ itemSource: '123',
+ file: 'shared_folder',
+ expiration: '2017-10-12',
+ emailBody: '',
+ bccSelf: 'false'
+ });
fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
+ 200, {
+ 'Content-Type': 'application/json'
+ },
JSON.stringify({
status: 'success',
data: [
@@ -108,40 +120,34 @@ describe('OC.Share.ShareDialogMailView', function() {
);
expect(callback.calledOnce).toEqual(true);
- expect(callback.getCall(0).args[0]).toEqual([
- 'someresult1',
- 'someresult2'
- ]);
-
});
- });
-
- describe('sending emails', function() {
- it('sends entered emails when calling sendEmails()', function() {
+ it('sends mail to self if BCC is checked', function() {
var callback = sinon.stub();
- view.$('.emailField').val('email@example.com');
+ view.$('.emailPrivateLinkForm--emailField').val('GlaDOS@aperture.com');
+ view.$('.emailPrivateLinkForm--emailBccSelf').prop('checked', 'checked');
+ view.$('.emailPrivateLinkForm--emailBodyField').val('The Cake Is A Lie!');
view.sendEmails().then(callback);
expect(callback.notCalled).toEqual(true);
-
expect(fakeServer.requests.length).toEqual(1);
-
expect(fakeServer.requests[0].method).toEqual('POST');
- expect(fakeServer.requests[0].url)
- .toEqual(OC.generateUrl('core/ajax/share.php'));
+ expect(fakeServer.requests[0].url).toEqual(OC.generateUrl('core/ajax/share.php'));
expect(OC.parseQueryString(fakeServer.requests[0].requestBody)).toEqual({
action: 'email',
- toaddress: 'email@example.com',
+ toAddress: 'glados@aperture.com',
link: model.getLink(),
itemType: 'folder',
itemSource: '123',
file: 'shared_folder',
- expiration: '2017-10-12'
+ expiration: '2017-10-12',
+ emailBody: 'The Cake Is A Lie!',
+ bccSelf: 'true'
});
fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
+ 200, {
+ 'Content-Type': 'application/json'
+ },
JSON.stringify({
status: 'success',
data: [
@@ -161,15 +167,16 @@ describe('OC.Share.ShareDialogMailView', function() {
it('rejects promise in case of failure', function() {
var callback = sinon.stub();
var rejectCallback = sinon.stub();
- view.$('.emailField').val('email@example.com');
+ view.$('.emailPrivateLinkForm--emailField').val('email@example.com');
view.sendEmails().then(callback).fail(rejectCallback);
expect(callback.notCalled).toEqual(true);
expect(fakeServer.requests.length).toEqual(1);
fakeServer.requests[0].respond(
- 200,
- { 'Content-Type': 'application/json' },
+ 200, {
+ 'Content-Type': 'application/json'
+ },
JSON.stringify({
status: 'error',
data: {
diff --git a/lib/private/Share/MailNotifications.php b/lib/private/Share/MailNotifications.php
index 033d3ffa0f56..b605c25b1fdc 100644
--- a/lib/private/Share/MailNotifications.php
+++ b/lib/private/Share/MailNotifications.php
@@ -87,6 +87,19 @@ public function __construct(IUser $user,
$this->senderDisplayName = $this->user->getDisplayName();
}
+ /**
+ * split a list of comma or semicolon separated email addresses
+ *
+ * @param string $mailsstring email addresses
+ * @return array list of individual addresses
+ */
+ private function _mailStringToArray($mailsstring) {
+ $sanatised = str_replace([', ', '; ', ',', ';', ' '], ',', $mailsstring);
+ $mail_array = explode(',', $sanatised);
+
+ return $mail_array;
+ }
+
/**
* inform users if a file was shared with them
*
@@ -156,26 +169,42 @@ public function sendInternalShareMail($recipientList, $itemSource, $itemType) {
}
+ public function sendLinkShareMail($recipient, $filename, $link, $expiration) {
+ $subject = (string)$this->l->t('%s shared »%s« with you', [$this->senderDisplayName, $filename]);
+ list($htmlBody, $textBody) = $this->createMailBody($filename, $link, $expiration);
+
+ return $this->sendLinkShareMailFromBody($recipient, $subject, $htmlBody, $textBody);
+ }
+
/**
* inform recipient about public link share
*
* @param string $recipient recipient email address
* @param string $filename the shared file
* @param string $link the public link
+ * @param array $options allows ['cc'] and ['bcc'] recipients
* @param int $expiration expiration date (timestamp)
* @return string[] $result of failed recipients
*/
- public function sendLinkShareMail($recipient, $filename, $link, $expiration) {
- $subject = (string)$this->l->t('%s shared »%s« with you', [$this->senderDisplayName, $filename]);
- list($htmlBody, $textBody) = $this->createMailBody($filename, $link, $expiration);
+ public function sendLinkShareMailFromBody($recipient, $subject, $htmlBody, $textBody, $options = array()) {
+
+ $recipients = $this->_mailStringToArray($recipient);
+ $ccRecipients = (isset($options['cc']) && $options['cc'] !== '') ? $this->_mailStringToArray($options['cc']) : null;
+ $bccRecipients = (isset($options['bcc']) && $options['bcc'] !== '') ? $this->_mailStringToArray($options['bcc']) : null;
- $recipient = str_replace([', ', '; ', ',', ';', ' '], ',', $recipient);
- $recipients = explode(',', $recipient);
try {
$message = $this->mailer->createMessage();
$message->setSubject($subject);
$message->setTo($recipients);
- $message->setHtmlBody($htmlBody);
+ if ($htmlBody !== null) {
+ $message->setHtmlBody($htmlBody);
+ }
+ if ($bccRecipients !== null) {
+ $message->setBcc($bccRecipients);
+ }
+ if ($ccRecipients !== null) {
+ $message->setCc($ccRecipients);
+ }
$message->setPlainBody($textBody);
$message->setFrom([
Util::getDefaultEmailAddress('sharing-noreply') =>
@@ -204,7 +233,7 @@ public function sendLinkShareMail($recipient, $filename, $link, $expiration) {
* @param string $prefix prefix of mail template files
* @return array an array of the html mail body and the plain text mail body
*/
- private function createMailBody($filename, $link, $expiration, $prefix = '') {
+ public function createMailBody($filename, $link, $expiration, $prefix = '') {
$formattedDate = $expiration ? $this->l->l('date', $expiration) : null;
$html = new \OC_Template('core', $prefix . 'mail', '');
diff --git a/tests/ui/features/lib/FilesPageElement/SharingDialogElement/EditPublicLinkPopup.php b/tests/ui/features/lib/FilesPageElement/SharingDialogElement/EditPublicLinkPopup.php
index 4f9f7afed3d6..982c0a7f2292 100644
--- a/tests/ui/features/lib/FilesPageElement/SharingDialogElement/EditPublicLinkPopup.php
+++ b/tests/ui/features/lib/FilesPageElement/SharingDialogElement/EditPublicLinkPopup.php
@@ -41,7 +41,7 @@ class EditPublicLinkPopup extends OwncloudPage {
private $expirationDateLabelXpath = ".//label[contains(text(), 'Expiration')]";
private $expirationDateInputXpath = ".//input[contains(@class,'expirationDate')]";
private $emailInputXpath = ".//input[@type='email']";
- private $saveButtonXpath = ".//button[contains(text(), 'Save')]";
+ private $shareButtonXpath = ".//button[contains(text(), 'Share')]";
/**
@@ -184,11 +184,11 @@ public function setLinkEmail($email) {
* @return void
*/
public function save() {
- $saveButton = $this->popupElement->find("xpath", $this->saveButtonXpath);
+ $saveButton = $this->popupElement->find("xpath", $this->shareButtonXpath);
if (is_null($saveButton)) {
throw new ElementNotFoundException(
__METHOD__ .
- " xpath $this->saveButtonXpath" .
+ " xpath $this->shareButtonXpath" .
" could not find save button of the public link popup"
);
}