Compare commits

...

74 Commits

Author SHA1 Message Date
Joas Schilling d96adc01b7 Merge pull request #11361 from nextcloud/rel-14.0.1
Increase version for 14.0.1
2018-09-25 08:33:42 +02:00
Joas Schilling 884ac1e117 Increase version for 14.0.1
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-09-25 08:19:39 +02:00
Morris Jobke c35401110a Merge pull request #11340 from nextcloud/stable14-add-unit-test-findlanguagefromlocale
[14] Add unit test for findLanguageFromLocale
2018-09-24 12:20:31 +02:00
Daniel Kesselberg 62b9ae21fe Add simple unit test for findLanguageFromLocale
Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
2018-09-23 23:15:05 +02:00
Joas Schilling 1f714124bb Merge pull request #11259 from nextcloud/fix/11144/backport14
[14] Fixes empty favorite names for trailing slashes
2018-09-20 13:43:24 +02:00
Joas Schilling 4d8f69f7a4 Merge pull request #11173 from nextcloud/update-version-14.0.1
Prepare 14.0.1 release
2018-09-20 12:48:49 +02:00
Joas Schilling e77bd8a894 Prepare 14.0.1 release
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-09-20 10:58:49 +02:00
blizzz ea73f30d77 Merge pull request #11302 from nextcloud/backport/11297/this-database-dude
[stable14] Fix expiration code of tokens
2018-09-20 10:52:15 +02:00
blizzz 0c85cb1ea9 Merge pull request #11077 from nextcloud/stable14-11064-fix-markup-and-style-of-mentions-in-comments
[stable14] Fix markup and style of mentions in comments
2018-09-20 10:37:23 +02:00
blizzz a0f2bd8d28 Merge pull request #11294 from nextcloud/stable14-locale-template-fix
[stable14] Use user locale as default in the template
2018-09-20 10:37:00 +02:00
Joas Schilling e5176960ce Merge pull request #11288 from nextcloud/backport/11171/shared-by-info-for-room-shares-without-names
[stable14] Shared by info for room shares without names
2018-09-20 10:26:18 +02:00
Joas Schilling 9a4ad9cd17 Merge pull request #11287 from nextcloud/backport/11041/get_permission_of_storage_for_shares
[stable14] Get permission of storage for shares
2018-09-20 10:25:34 +02:00
Joas Schilling 2153bcfea8 Merge pull request #11293 from nextcloud/backport/11292/do-not-apcu-cache-the-autoloader
[stable14] Revert "Use APCu caching of composer"
2018-09-20 10:08:02 +02:00
Joas Schilling 6718bfb83d Also adjust the expiration of PublicKeyTokenProvider
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-09-20 10:00:08 +02:00
Joas Schilling 3a179b2519 Copy the expiration from 480864b3e3 to getTokenById
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-09-20 09:59:53 +02:00
blizzz 8dff9460b8 Merge pull request #11291 from nextcloud/stable14-fix-icons-cacher
[stable14] Fix icons cacher regex for compressed output
2018-09-19 22:40:15 +02:00
Michael Weimann 43889d1a49 Fixes empty favorite names for trailing slashes
Signed-off-by: Michael Weimann <mail@michael-weimann.eu>
2018-09-19 17:44:54 +02:00
John Molakvoæ (skjnldsv) fcda1f7124 Fix since tag
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
2018-09-19 16:13:26 +02:00
John Molakvoæ (skjnldsv) efbd98183d Fallback to $lang if no $locale match
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
2018-09-19 16:13:22 +02:00
John Molakvoæ (skjnldsv) d69ddd94de Typehint
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
2018-09-19 16:13:19 +02:00
John Molakvoæ (skjnldsv) ccb8838854 Since requirement
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
2018-09-19 16:13:14 +02:00
John Molakvoæ (skjnldsv) 19350c4b95 Fix public l10n
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
2018-09-19 16:13:10 +02:00
John Molakvoæ (skjnldsv) 258330d64d Use user locale as default in the template
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
2018-09-19 16:13:06 +02:00
Joas Schilling c02c63f53a Merge pull request #11282 from nextcloud/backport/11183/fix-link-for-update-notifications
[stable14] Fix the link and anchor for the update notifications
2018-09-19 15:59:25 +02:00
Joas Schilling 86a2d1fecd Revert "Use APCu caching of composer"
This reverts commit 948ab8a4d0.

For details why see https://github.com/nextcloud/server/issues/11290
2018-09-19 15:56:30 +02:00
John Molakvoæ (skjnldsv) e2991d55c7 Fix icons cacher regex for compressed output
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
2018-09-19 15:47:33 +02:00
blizzz bea36f9992 Merge pull request #11283 from nextcloud/stable14-11268-include-empty-directories-in-the-default-state-of-acceptance-tests
[stable14] Include empty directories in the default state of acceptance tests
2018-09-19 15:24:28 +02:00
blizzz 64d8f74c32 Merge pull request #11280 from nextcloud/backport/11080/stable14
[stable14] replace setcookie value with '' instead of null.
2018-09-19 15:18:01 +02:00
blizzz cfca80ef69 Merge pull request #11277 from nextcloud/stable14-11257-prevent-comment-being-composed-from-overlapping-the-submit-button
[stable14] Prevent comment being composed from overlapping the submit button
2018-09-19 15:17:12 +02:00
blizzz 27a3867094 Merge pull request #11276 from nextcloud/stable14-11054-fix-size-of-icons-in-menus-inside-apps-when-shown-as-images
[stable14] Fix size of icons in menus inside apps when shown as images
2018-09-19 15:16:23 +02:00
Joas Schilling 7b3e3ee898 Better shared-by info for conversations without names
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-09-19 13:46:13 +02:00
Roeland Jago Douma 5e13368299 Update test now that we check permissions properly
Now that we actually check thepermissions properly we have to update the
tests.

* We checked an invalid path
* We checked from wrong permissions (files never have CREATE permissions
for example)

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-09-19 13:28:21 +02:00
Roeland Jago Douma b66b2de6ff Properly check share permissions
isCreatable only works on folders
isUpdatable if the file is not there but it is a part file also has to
be checked on the folder

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-09-19 13:28:13 +02:00
Roeland Jago Douma 43f73ad808 Fix shared cache
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-09-19 13:28:04 +02:00
Roeland Jago Douma 4cc8cdc276 Check the permission of the underlying storage
Else shares might expose more permissions than the storage actually
providers.

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-09-19 13:27:57 +02:00
Daniel Calviño Sánchez 3a30fa1235 Include empty directories in the default state of acceptance tests
Before each scenario of the acceptance tests is run the Nextcloud server
is reset to a default state. To do this the full directory of the
Nextcloud server is commited to a local Git repository and then reset to
that commit when needed.

Unfortunately, Git does not support including empty directories in a
commit. Due to this, when the default state was restored, it could
happen that the file cache listed an empty directory that did not exist
because it was not properly restored (for example,
"data/appdata_*/css/icons"), and that in turn could lead to an error
when the directory was used.

Currently the only way to force Git to include an empty directory is to
add a dummy file to the directory (so it will no longer be empty,
but that should not be a problem in the affected directories, even if
the dummy file is not included in the file cache); although Git FAQ
suggests using a ".gitignore" file a ".keep" file was used instead, as
it conveys better its purpose.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-09-19 12:50:32 +02:00
Joas Schilling d50fa1bdb8 Fix the link and anchor for the update notifications
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-09-19 12:12:13 +02:00
MartB fbc1f5cd38 replace setcookie value with '' instead of null.
The php documentation states that an empty string should be used for a cookie when it has no real value.
null leads to the following error: expects parameter 2 to be string, null given

Signed-off-by: Martin Böh <mart.b@outlook.de>
2018-09-19 11:47:40 +02:00
Daniel Calviño Sánchez 896c8df6ad Prevent comment being composed from overlapping the submit button
The submit button is placed in the text area using absolute positioning,
so it is not taken into account when calculating the text layout. Due to
this it is necessary to add an explicit padding to the right of the text
area to prevent the text from overlapping the submit button.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-09-19 08:51:42 +02:00
Daniel Calviño Sánchez a9fa17eb7e Fix size of icons in menus inside apps when shown as images
Some popover menus, like the contacts menu, still show their icon using
an img element. The main CSS rules assume that a "content-box" sizing is
being used, and thus set the size and padding of the image to add up to
the line height.

However, ".app-*" descendants use a "border-box" sizing, so when a menu
with an image was shown in an app the icon was not properly shown. Now
both the width and height of the image is set to the item height in
those cases, which causes the visible size of the icon to be the item
height minus the padding (the same as when "content-box" sizing is
used).

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-09-19 08:46:53 +02:00
Joas Schilling fb9379db3e Merge pull request #11237 from nextcloud/backport/11042/stable14
[stable14] Remove filter_var flags due to PHP 7.3 deprecation, fixes #10894
2018-09-17 10:10:54 +02:00
Patrik Kernstock 5058333445 Remove filter_var flags due to PHP 7.3 deprecation, fixes #10894
Signed-off-by: Patrik Kernstock <info@pkern.at>
2018-09-16 04:45:15 +02:00
Joas Schilling 5bf377463e Merge pull request #11201 from nextcloud/backport/11036/stable14
[stable14]  fix check for more users in sharing dialogue
2018-09-13 11:21:08 +02:00
blizzz 2823d7a6f5 Merge pull request #11191 from nextcloud/backport/11091-cannot-read-passwd
[14] Remove posix_getpwuid and compare only userid
2018-09-13 10:32:29 +02:00
Arthur Schiwon 72588b69bb Backport of #11036 to stable14
fix check for more users

after a refactor users et al were undefined. The check condition was moved.

Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>

don't user a higher paging size than max autocomplete entries are set

Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>

adjust and extend js unit tests

Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
2018-09-13 10:20:55 +02:00
Daniel Kesselberg 843df1c009 Add int-typehint
Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
2018-09-12 15:08:30 +02:00
Daniel Kesselberg 53ecdfec51 Remove posix_getpwuid and compare only userid
Signed-off-by: Daniel Kesselberg <mail@danielkesselberg.de>
2018-09-12 15:08:19 +02:00
blizzz 4165f332de Merge pull request #11187 from nextcloud/backport/11133/invalid-exception
[stable14] Fix exception class
2018-09-12 13:21:50 +02:00
blizzz 8e3e25a057 Merge pull request #11186 from nextcloud/backport/11181/user-list-broken-with-integer-only-users
[stable14] Fix user and group listing with users that have an integer user id
2018-09-12 13:17:13 +02:00
Joas Schilling 2518cdd2d9 Fix exception class
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-09-12 11:57:43 +02:00
Joas Schilling 73e870bd78 Fix user and group listing with users that have an integer user id
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-09-12 11:54:22 +02:00
John Molakvoæ 5209348c64 Merge pull request #11152 from nextcloud/davclient-js-decode-14
[14] fix js files client for user names with spaces
2018-09-11 10:46:12 +02:00
Robin Appelman 9b64c27ce2 fix js files client for user names with spaces
Signed-off-by: Robin Appelman <robin@icewind.nl>
2018-09-10 22:39:06 +02:00
Roeland Jago Douma e296f7d348 Merge pull request #11090 from nextcloud/backport/11082/stable14
[stable14] Do not invalidate main token on OAuth
2018-09-07 13:59:45 +02:00
Roeland Jago Douma 5b89eff367 Merge pull request #11103 from nextcloud/backport/token_expire_hardening
[stable14] Expire tokens hardening
2018-09-07 13:59:10 +02:00
Roeland Jago Douma b580ef18c8 Merge pull request #11039 from nextcloud/backport/fix/10968/upload-progress
Fixes the upload progress bar layout - 14 backport
2018-09-07 13:58:58 +02:00
Roeland Jago Douma c83ac2472d Expire tokens hardening
Just to be sure that the field is also not 0

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-09-07 10:02:56 +02:00
Roeland Jago Douma 54859329ef Do not invalidate main token on OAuth
Fixes #10584

We deleted the main token when using the login flow else mutliple tokens
would show up for a single user.

However in the case of OAuth this is perfectly fine as the
authentication happens really in your browser:

1. You are already logged in, no need to log you out
2. You are not logged in yet, but since you log in into the exact same
browser the expected behavior is to stay logged in.

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-09-06 13:28:48 +02:00
Roeland Jago Douma 1b35dc1cba Merge pull request #11069 from nextcloud/release/14.0.0
14.0.0 final
2018-09-06 09:25:18 +02:00
Roeland Jago Douma b619e8ddde 14.0.0 final
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-09-06 08:35:10 +02:00
Daniel Calviño Sánchez 51b978d3f0 Add new line at the end of file
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-09-05 20:59:02 +02:00
Daniel Calviño Sánchez 2e424d84a4 Ensure that the avatar and the user name will be kept together
Otherwise a line break could be added between the avatar and the user
name when the wrapper is close to the right border of the message.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-09-05 20:59:02 +02:00
Daniel Calviño Sánchez e7d4d3a34b Remove unneeded CSS rule for mentions
Most of the properties of the rule are not needed for mentions, so the
rule is no longer applied to them; the only needed property was moved to
the main rule for mentions.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-09-05 20:59:02 +02:00
Daniel Calviño Sánchez 7c851b5b77 Fix pointer cursor not shown on avatars
When the cursor is on an avatar wrapper the cursor is shown as a pointer
to inform the user that it can be clicked (which will either show the
contacts menu or insert a mention, depending on the case); the cursor
must be explicitly defined for the "img" element that shows the avatar
too, or otherwise the default cursor would be shown.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-09-05 20:59:02 +02:00
Daniel Calviño Sánchez b14425ef6f Highlight mentions to the current user
Like done in Talk, mentions to the current user are now shown with the
primary colors to make them more prominent.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-09-05 20:59:02 +02:00
Daniel Calviño Sánchez 3c63850117 Ensure that the user name is shown in bold in mentions
Different browsers use different font weights for strong elements
(Chromium uses "bold", but Firefox uses "bolder", which is relative to
the font weight of the parent), so now the user name in mentions is
explicitly shown with a bold weight.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-09-05 20:59:02 +02:00
Daniel Calviño Sánchez 6b7e049288 Reformat embedded HTML code to resemble HTML code
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-09-05 20:59:02 +02:00
Daniel Calviño Sánchez 3ee07ac770 Remove space between avatar and user name
The avatar should be shown immediately after the avatar to be able to
accurately define the space between them using only CSS rules.

Note that in the case of the "atwho" menu it is not really needed, as a
whitespace removal seems to be done automatically by the plugin, but it
was modified for its displayed elements too for consistency.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-09-05 20:59:02 +02:00
Daniel Calviño Sánchez da75c7ff6d Show avatar using "span" instead of "div"
Visually it makes no difference, but as the ".avatar" element is inside
a "span" element it can not be a block element to be compliant with the
HTML specification.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-09-05 20:59:02 +02:00
Georg Ehrke 4173f9d588 Merge pull request #11071 from nextcloud/bugfix-stable14/10727
[stable14] remove LogicException, because it's also triggered with legitimate pa…
2018-09-05 18:08:55 +02:00
Georg Ehrke 2bdc407a82 remove LogicException, because it's also triggered with legitimate parameters
Signed-off-by: Georg Ehrke <developer@georgehrke.com>
2018-09-05 14:12:27 +02:00
Roeland Jago Douma b08f67085d Merge pull request #11052 from nextcloud/backport/10963/stable14
[stable14] Updates logo scss to regard default values
2018-09-05 10:30:29 +02:00
Michael Weimann b0d9030388 Updates logo scss to regard default values
Signed-off-by: Michael Weimann <mail@michael-weimann.eu>
2018-09-04 21:27:45 +02:00
Michael Weimann 209b3bee68 Fixes the upload progress bar layout
Signed-off-by: Michael Weimann <mail@michael-weimann.eu>
2018-09-03 21:13:28 +02:00
39 changed files with 534 additions and 190 deletions
+25 -3
View File
@@ -22,6 +22,9 @@
padding: 10px;
min-height: 44px;
margin: 0;
/* Prevent the text from overlapping with the submit button. */
padding-right: 30px;
}
#commentsTabView .newCommentForm {
@@ -130,7 +133,7 @@
adding this brings them closer to the element**/
margin-top: 5px;
}
#commentsTabView .comments li .message .avatar-name-wrapper,
.atwho-view-ul * .avatar-name-wrapper,
#commentsTabView .comment .authorRow {
position: relative;
@@ -141,24 +144,34 @@
#commentsTabView .comment:not(.newCommentRow) .message .avatar-name-wrapper:not(.currentUser),
#commentsTabView .comment:not(.newCommentRow) .message .avatar-name-wrapper:not(.currentUser) .avatar,
#commentsTabView .comment:not(.newCommentRow) .message .avatar-name-wrapper:not(.currentUser) .avatar img,
#commentsTabView .comment .authorRow .avatar:not(.currentUser),
#commentsTabView .comment .authorRow .author:not(.currentUser) {
cursor: pointer;
}
.atwho-view-ul .avatar-name-wrapper,
.atwho-view-ul .avatar-name-wrapper .avatar {
.atwho-view-ul .avatar-name-wrapper .avatar,
.atwho-view-ul .avatar-name-wrapper .avatar img {
cursor: pointer;
}
#commentsTabView .comments li .message .atwho-inserted,
#commentsTabView .newCommentForm .atwho-inserted {
.avatar-name-wrapper {
/* Make the wrapper the positioning context of its child contacts
* menu. */
position: relative;
display: inline;
vertical-align: top;
background-color: var(--color-background-dark);
border-radius: 50vh;
padding: 1px 7px 1px 1px;
/* Ensure that the avatar and the user name will be kept together. */
white-space: nowrap;
.avatar {
img {
vertical-align: top;
@@ -171,6 +184,15 @@
margin-left: 0;
margin-right: 2px;
}
strong {
/* Ensure that the user name is shown in bold, as different browsers
* use different font weights for strong elements. */
font-weight: bold;
}
}
.avatar-name-wrapper.currentUser {
background-color: var(--color-primary);
color: var(--color-primary-text);
}
}
@@ -231,4 +253,4 @@
.app-files .action-comment {
padding: 16px 14px;
}
}
+32 -28
View File
@@ -196,24 +196,26 @@
sorter: function (q, items) { return items; }
},
displayTpl: function (item) {
return '<li>'
+ '<span class="avatar-name-wrapper">'
+ '<div class="avatar" '
+ ' data-username="' + escapeHTML(item.id) + '"' // for avatars
+ ' data-user="' + escapeHTML(item.id) + '"' // for contactsmenu
+ ' data-user-display-name="' + escapeHTML(item.label) + '"></div>'
+ ' <strong>' + escapeHTML(item.label) + '</strong>'
+ '</span></li>';
return '<li>' +
'<span class="avatar-name-wrapper">' +
'<span class="avatar" ' +
'data-username="' + escapeHTML(item.id) + '" ' + // for avatars
'data-user="' + escapeHTML(item.id) + '" ' + // for contactsmenu
'data-user-display-name="' + escapeHTML(item.label) + '">' +
'</span>' +
'<strong>' + escapeHTML(item.label) + '</strong>' +
'</span></li>';
},
insertTpl: function (item) {
return ''
+ '<span class="avatar-name-wrapper">'
+ '<div class="avatar" '
+ ' data-username="' + escapeHTML(item.id) + '"' // for avatars
+ ' data-user="' + escapeHTML(item.id) + '"' // for contactsmenu
+ ' data-user-display-name="' + escapeHTML(item.label) + '"></div>'
+ ' <strong>' + escapeHTML(item.label) + '</strong>'
+ '</span>';
return '' +
'<span class="avatar-name-wrapper">' +
'<span class="avatar" ' +
'data-username="' + escapeHTML(item.id) + '" ' + // for avatars
'data-user="' + escapeHTML(item.id) + '" ' + // for contactsmenu
'data-user-display-name="' + escapeHTML(item.label) + '">' +
'</span>' +
'<strong>' + escapeHTML(item.label) + '</strong>' +
'</span>';
},
searchKey: "label"
});
@@ -224,7 +226,7 @@
// passing the whole comments form would re-apply and request
// avatars from the server
$(je.target).find(
'div[data-username="' + $el.find('[data-username]').data('username') + '"]'
'span[data-username="' + $el.find('[data-username]').data('username') + '"]'
).parent(),
editionMode
);
@@ -486,20 +488,22 @@
},
_composeHTMLMention: function(uid, displayName) {
var avatar = '<div class="avatar" '
+ 'data-username="' + _.escape(uid) + '"'
+ ' data-user="' + _.escape(uid) + '"'
+ ' data-user-display-name="'
+ _.escape(displayName) + '"></div>';
var avatar = '' +
'<span class="avatar" ' +
'data-username="' + _.escape(uid) + '" ' +
'data-user="' + _.escape(uid) + '" ' +
'data-user-display-name="' + _.escape(displayName) + '">' +
'</span>';
var isCurrentUser = (uid === OC.getCurrentUser().uid);
return ''
+ '<span class="atwho-inserted" contenteditable="false">'
+ '<span class="avatar-name-wrapper' + (isCurrentUser ? ' currentUser' : '') + '">'
+ avatar + ' <strong>'+ _.escape(displayName)+'</strong>'
+ '</span>'
+ '</span>';
return '' +
'<span class="atwho-inserted" contenteditable="false">' +
'<span class="avatar-name-wrapper' + (isCurrentUser ? ' currentUser' : '') + '">' +
avatar +
'<strong>' + _.escape(displayName) + '</strong>' +
'</span>' +
'</span>';
},
nextPage: function() {
@@ -309,7 +309,7 @@ describe('OCA.Comments.CommentsTabView tests', function() {
expect(createStub.calledOnce).toEqual(false);
expect($newCommentForm.find('.message').html()).toContain('Mention to <span');
expect($newCommentForm.find('.message').html()).toContain('<div class="avatar"');
expect($newCommentForm.find('.message').html()).toContain('<span class="avatar"');
expect($newCommentForm.find('.message').html()).toContain('<strong>User Name</strong>');
expect($newCommentForm.find('.message').text()).not.toContain('@');
// In this case the default behaviour is prevented by the
+9 -5
View File
@@ -28,10 +28,16 @@ class Plugin extends \Sabre\CalDAV\Plugin {
const SYSTEM_CALENDAR_ROOT = 'system-calendars';
/**
* @inheritdoc
* Returns the path to a principal's calendar home.
*
* The return url must not end with a slash.
* This function should return null in case a principal did not have
* a calendar home.
*
* @param string $principalUrl
* @return string|null
*/
function getCalendarHomeForPrincipal($principalUrl):string {
function getCalendarHomeForPrincipal($principalUrl) {
if (strrpos($principalUrl, 'principals/users', -strlen($principalUrl)) !== false) {
list(, $principalId) = \Sabre\Uri\split($principalUrl);
return self::CALENDAR_ROOT . '/' . $principalId;
@@ -44,8 +50,6 @@ class Plugin extends \Sabre\CalDAV\Plugin {
list(, $principalId) = \Sabre\Uri\split($principalUrl);
return self::SYSTEM_CALENDAR_ROOT . '/calendar-rooms/' . $principalId;
}
throw new \LogicException('This is not supposed to happen');
}
}
+1 -4
View File
@@ -39,10 +39,9 @@ class Plugin extends \Sabre\CardDAV\Plugin {
* Returns the addressbook home for a given principal
*
* @param string $principal
* @return string
* @return string|null
*/
protected function getAddressbookHomeForPrincipal($principal) {
if (strrpos($principal, 'principals/users', -strlen($principal)) !== false) {
list(, $principalId) = \Sabre\Uri\split($principal);
return self::ADDRESSBOOK_ROOT . '/users/' . $principalId;
@@ -55,8 +54,6 @@ class Plugin extends \Sabre\CardDAV\Plugin {
list(, $principalId) = \Sabre\Uri\split($principal);
return self::ADDRESSBOOK_ROOT . '/system/' . $principalId;
}
throw new \LogicException('This is not supposed to happen');
}
/**
+1 -5
View File
@@ -63,11 +63,7 @@ class PluginTest extends TestCase {
$this->assertSame($expected, $this->plugin->getCalendarHomeForPrincipal($input));
}
/**
* @expectedException \LogicException
* @expectedExceptionMessage This is not supposed to happen
*/
public function testGetCalendarHomeForUnknownPrincipal() {
$this->plugin->getCalendarHomeForPrincipal('FOO/BAR/BLUB');
$this->assertNull($this->plugin->getCalendarHomeForPrincipal('FOO/BAR/BLUB'));
}
}
+4
View File
@@ -44,6 +44,10 @@
height: 36px;
display:inline-block;
text-align: center;
.ui-progressbar-value {
margin: 0;
}
}
#uploadprogressbar .ui-progressbar-value.ui-widget-header.ui-corner-left {
height: 100%;
+1 -2
View File
@@ -176,7 +176,6 @@ class ViewController extends Controller {
$currentCount = 0;
foreach ($favElements['folders'] as $dir) {
$id = substr($dir, strrpos($dir, '/') + 1, strlen($dir));
$link = $this->urlGenerator->linkToRoute('files.view.index', ['dir' => $dir, 'view' => 'files']);
$sortingValue = ++$currentCount;
$element = [
@@ -186,7 +185,7 @@ class ViewController extends Controller {
'dir' => $dir,
'order' => $navBarPositionPosition,
'folderPosition' => $sortingValue,
'name' => $id,
'name' => basename($dir),
'icon' => 'files',
'quickaccesselement' => 'true'
];
@@ -176,8 +176,53 @@ class ViewControllerTest extends TestCase {
'active' => false,
'icon' => '',
'type' => 'link',
'classes' => '',
'sublist' => [],
'classes' => 'collapsible',
'sublist' => [
[
'id' => '-test1',
'view' => 'files',
'href' => '',
'dir' => '/test1',
'order' => 6,
'folderPosition' => 1,
'name' => 'test1',
'icon' => 'files',
'quickaccesselement' => 'true',
],
[
'name' => 'test2',
'id' => '-test2-',
'view' => 'files',
'href' => '',
'dir' => '/test2/',
'order' => 7,
'folderPosition' => 2,
'icon' => 'files',
'quickaccesselement' => 'true',
],
[
'name' => 'sub4',
'id' => '-test3-sub4',
'view' => 'files',
'href' => '',
'dir' => '/test3/sub4',
'order' => 8,
'folderPosition' => 3,
'icon' => 'files',
'quickaccesselement' => 'true',
],
[
'name' => 'sub6',
'id' => '-test5-sub6-',
'view' => 'files',
'href' => '',
'dir' => '/test5/sub6/',
'order' => 9,
'folderPosition' => 4,
'icon' => 'files',
'quickaccesselement' => 'true',
],
],
'defaultExpandedState' => false,
'expandedState' => 'show_Quick_Access'
],
@@ -303,6 +348,22 @@ class ViewControllerTest extends TestCase {
'id' => 'shareoverview',
'content' => null,
],
'-test1' => [
'id' => '-test1',
'content' => '',
],
'-test2-' => [
'id' => '-test2-',
'content' => '',
],
'-test3-sub4' => [
'id' => '-test3-sub4',
'content' => '',
],
'-test5-sub6-' => [
'id' => '-test5-sub6-',
'content' => '',
],
],
'hiddenFields' => [],
]
@@ -315,7 +376,12 @@ class ViewControllerTest extends TestCase {
->with($this->user->getUID())
->willReturn([
'item' => [],
'folders' => [],
'folders' => [
'/test1',
'/test2/',
'/test3/sub4',
'/test5/sub6/',
],
]);
$this->assertEquals($expected, $this->viewController->index('MyDir', 'MyView'));
+1 -1
View File
@@ -142,7 +142,7 @@ class Cache extends CacheJail {
} else {
$entry['path'] = $path;
}
$sharePermissions = $this->storage->getPermissions($path);
$sharePermissions = $this->storage->getPermissions($entry['path']);
if (isset($entry['permissions'])) {
$entry['permissions'] &= $sharePermissions;
} else {
+10 -3
View File
@@ -195,7 +195,8 @@ class SharedStorage extends \OC\Files\Storage\Wrapper\Jail implements ISharedSto
if (!$this->isValid()) {
return 0;
}
$permissions = $this->superShare->getPermissions();
$permissions = parent::getPermissions($target) & $this->superShare->getPermissions();
// part files and the mount point always have delete permissions
if ($target === '' || pathinfo($target, PATHINFO_EXTENSION) === 'part') {
$permissions |= \OCP\Constants::PERMISSION_DELETE;
@@ -257,11 +258,17 @@ class SharedStorage extends \OC\Files\Storage\Wrapper\Jail implements ISharedSto
case 'xb':
case 'a':
case 'ab':
$creatable = $this->isCreatable($path);
$creatable = $this->isCreatable(dirname($path));
$updatable = $this->isUpdatable($path);
// if neither permissions given, no need to continue
if (!$creatable && !$updatable) {
return false;
if (pathinfo($path, PATHINFO_EXTENSION) === 'part') {
$updatable = $this->isUpdatable(dirname($path));
}
if (!$updatable) {
return false;
}
}
$exists = $this->file_exists($path);
+7 -7
View File
@@ -134,14 +134,14 @@ class PermissionsTest extends TestCase {
* Test that the permissions of shared directory are returned correctly
*/
function testGetPermissions() {
$sharedDirPerms = $this->sharedStorage->getPermissions('shareddir');
$sharedDirPerms = $this->sharedStorage->getPermissions('');
$this->assertEquals(31, $sharedDirPerms);
$sharedDirPerms = $this->sharedStorage->getPermissions('shareddir/textfile.txt');
$this->assertEquals(31, $sharedDirPerms);
$sharedDirRestrictedPerms = $this->sharedStorageRestrictedShare->getPermissions('shareddirrestricted');
$this->assertEquals(7, $sharedDirRestrictedPerms);
$sharedDirRestrictedPerms = $this->sharedStorageRestrictedShare->getPermissions('shareddirrestricted/textfile.txt');
$this->assertEquals(7, $sharedDirRestrictedPerms);
$sharedDirPerms = $this->sharedStorage->getPermissions('textfile.txt');
$this->assertEquals(27, $sharedDirPerms);
$sharedDirRestrictedPerms = $this->sharedStorageRestrictedShare->getPermissions('');
$this->assertEquals(15, $sharedDirRestrictedPerms);
$sharedDirRestrictedPerms = $this->sharedStorageRestrictedShare->getPermissions('textfile1.txt');
$this->assertEquals(3, $sharedDirRestrictedPerms);
}
/**
@@ -74,7 +74,7 @@ class SettingsController extends Controller {
public function addClient(string $name,
string $redirectUri): JSONResponse {
if (filter_var($redirectUri, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED|FILTER_FLAG_HOST_REQUIRED) === false) {
if (filter_var($redirectUri, FILTER_VALIDATE_URL) === false) {
return new JSONResponse(['message' => $this->l->t('Your redirect URL needs to be a full URL for example: https://yourdomain.com/path')], Http::STATUS_BAD_REQUEST);
}
@@ -74,7 +74,7 @@ abstract class AUserData extends OCSController {
/**
* creates a array with all user data
*
* @param $userId
* @param string $userId
* @return array
* @throws OCSException
*/
@@ -186,26 +186,25 @@ class GroupsController extends AUserData {
* @throws OCSException
*/
public function getGroupUsersDetails(string $groupId, string $search = '', int $limit = null, int $offset = 0): DataResponse {
$user = $this->userSession->getUser();
$isSubadminOfGroup = false;
$currentUser = $this->userSession->getUser();
// Check the group exists
$group = $this->groupManager->get($groupId);
if ($group !== null) {
$isSubadminOfGroup =$this->groupManager->getSubAdmin()->isSubAdminOfGroup($user, $group);
$isSubadminOfGroup = $this->groupManager->getSubAdmin()->isSubAdminOfGroup($currentUser, $group);
} else {
throw new OCSException('The requested group could not be found', \OCP\API::RESPOND_NOT_FOUND);
}
// Check subadmin has access to this group
if($this->groupManager->isAdmin($user->getUID())
|| $isSubadminOfGroup) {
$users = $this->groupManager->get($groupId)->searchUsers($search, $limit, $offset);
if($this->groupManager->isAdmin($currentUser->getUID()) || $isSubadminOfGroup) {
$users = $group->searchUsers($search, $limit, $offset);
// Extract required number
$users = array_keys($users);
$usersDetails = [];
foreach ($users as $userId) {
foreach ($users as $user) {
/** @var IUser $user */
$userId = (string) $user->getUID();
$userData = $this->getUserData($userId);
// Do not insert empty entry
if(!empty($userData)) {
@@ -46,6 +46,7 @@ use OCP\IGroup;
use OCP\IGroupManager;
use OCP\ILogger;
use OCP\IRequest;
use OCP\IUser;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\L10N\IFactory;
@@ -154,29 +155,31 @@ class UsersController extends AUserData {
* returns a list of users and their data
*/
public function getUsersDetails(string $search = '', $limit = null, $offset = 0): DataResponse {
$user = $this->userSession->getUser();
$currentUser = $this->userSession->getUser();
$users = [];
// Admin? Or SubAdmin?
$uid = $user->getUID();
$uid = $currentUser->getUID();
$subAdminManager = $this->groupManager->getSubAdmin();
if ($this->groupManager->isAdmin($uid)){
$users = $this->userManager->search($search, $limit, $offset);
} else if ($subAdminManager->isSubAdmin($user)) {
$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($user);
$users = array_keys($users);
} else if ($subAdminManager->isSubAdmin($currentUser)) {
$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
foreach ($subAdminOfGroups as $key => $group) {
$subAdminOfGroups[$key] = $group->getGID();
}
$users = [];
foreach ($subAdminOfGroups as $group) {
$users = array_merge($users, $this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
$users[] = array_keys($this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
}
$users = array_merge(...$users);
}
$users = array_keys($users);
$usersDetails = [];
foreach ($users as $key => $userId) {
foreach ($users as $userId) {
$userId = (string) $userId;
$userData = $this->getUserData($userId);
// Do not insert empty entry
if (!empty($userData)) {
+2 -4
View File
@@ -174,9 +174,7 @@ class ThemingDefaults extends \OC_Defaults {
$legalLinks = ''; $divider = '';
foreach($links as $link) {
if($link['url'] !== ''
&& filter_var($link['url'], FILTER_VALIDATE_URL, [
'flags' => FILTER_FLAG_SCHEME_REQUIRED | FILTER_FLAG_HOST_REQUIRED
])
&& filter_var($link['url'], FILTER_VALIDATE_URL)
) {
$legalLinks .= $divider . '<a href="' . $link['url'] . '" class="legal" target="_blank"' .
' rel="noreferrer noopener">' . $link['text'] . '</a>';
@@ -339,7 +337,7 @@ class ThemingDefaults extends \OC_Defaults {
}
return false;
}
/**
* Increases the cache buster key
*/
@@ -108,7 +108,7 @@ class Notifier implements INotifier {
$notification->setParsedSubject($l->t('Update to %1$s is available.', [$parameters['version']]));
if ($this->isAdmin()) {
$notification->setLink($this->url->linkToRouteAbsolute('settings.AdminSettings.index') . '#updater');
$notification->setLink($this->url->linkToRouteAbsolute('settings.AdminSettings.index', ['section' => 'overview']) . '#version');
}
} else {
$appInfo = $this->getAppInfo($notification->getObjectType());
@@ -366,10 +366,10 @@ class ClientFlowLoginController extends Controller {
$serverPath = $protocol . "://" . $this->request->getServerHost() . $serverPostfix;
$redirectUri = 'nc://login/server:' . $serverPath . '&user:' . urlencode($loginName) . '&password:' . urlencode($token);
}
// Clear the token from the login here
$this->tokenProvider->invalidateToken($sessionId);
// Clear the token from the login here
$this->tokenProvider->invalidateToken($sessionId);
}
return new Http\RedirectResponse($redirectUri);
}
+21
View File
@@ -1043,6 +1043,27 @@ $popovericon-size: 16px;
}
}
/* "app-*" descendants use border-box sizing, so the height of the icon must be
* set to the height of the item (as well as its width to make it squared). */
#content[class*='app-'] {
.bubble,
.app-navigation-entry-menu,
.popovermenu {
li {
> button,
> a,
> .menuitem {
/* DEPRECATED! old img in popover fallback
* TODO: to remove */
> img {
width: $popoveritem-height;
height: $popoveritem-height;
}
}
}
}
}
/* CONTENT LIST ------------------------------------------------------------ */
.app-content-list {
width: 300px;
+3 -3
View File
@@ -19,7 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
// SCSS darken/lighten function override
@function nc-darken($color, $value) {
@return darken($color, $value);
@@ -60,8 +60,8 @@ $color-text-maxcontrast: nc-lighten($color-main-text, 46.2%) !default;
$color-text-light: nc-lighten($color-main-text, 15%) !default;
$color-text-lighter: nc-lighten($color-main-text, 30%) !default;
$image-logo: url('../img/logo.svg?v=1');
$image-login-background: url('../img/background.png?v=2');
$image-logo: url('../img/logo.svg?v=1') !default;
$image-login-background: url('../img/background.png?v=2') !default;
$color-loading-light: #ccc !default;
$color-loading-dark: #777 !default;
+1 -1
View File
@@ -271,7 +271,7 @@
* @return {Array.<FileInfo>} array of file info
*/
_parseFileInfo: function(response) {
var path = response.href;
var path = decodeURIComponent(response.href);
if (path.substr(0, this._root.length) === this._root) {
path = path.substr(this._root.length);
}
+22 -10
View File
@@ -100,16 +100,28 @@
{escape: false}
);
} else if (this.model.getReshareType() === OC.Share.SHARE_TYPE_ROOM) {
sharedByText = t(
'core',
'Shared with you and the conversation {conversation} by {owner}',
{
conversation: this.model.getReshareWithDisplayName(),
owner: ownerDisplayName
},
undefined,
{escape: false}
);
if (this.model.get('reshare').share_with_displayname) {
sharedByText = t(
'core',
'Shared with you and the conversation {conversation} by {owner}',
{
conversation: this.model.getReshareWithDisplayName(),
owner: ownerDisplayName
},
undefined,
{escape: false}
);
} else {
sharedByText = t(
'core',
'Shared with you in a conversation by {owner}',
{
owner: ownerDisplayName
},
undefined,
{escape: false}
);
}
} else {
sharedByText = t(
'core',
+21 -8
View File
@@ -326,7 +326,23 @@
var suggestions = exactMatches.concat(users).concat(groups).concat(remotes).concat(remoteGroups).concat(emails).concat(circles).concat(rooms).concat(lookup);
deferred.resolve(suggestions, exactMatches);
var moreResultsAvailable =
(
oc_config['sharing.maxAutocompleteResults'] > 0
&& Math.min(perPage, oc_config['sharing.maxAutocompleteResults'])
<= Math.max(
users.length + exactUsers.length,
groups.length + exactGroups.length,
remoteGroups.length + exactRemoteGroups.length,
remotes.length + exactRemotes.length,
emails.length + exactEmails.length,
circles.length + exactCircles.length,
rooms.length + exactRooms.length,
lookup.length
)
);
deferred.resolve(suggestions, exactMatches, moreResultsAvailable);
} else {
deferred.reject(result.ocs.meta.message);
}
@@ -380,12 +396,12 @@
$shareWithField.removeClass('error')
.tooltip('hide');
var perPage = 200;
var perPage = parseInt(oc_config['sharing.maxAutocompleteResults'], 10) || 200;
this._getSuggestions(
search.term.trim(),
perPage,
view.model
).done(function(suggestions) {
).done(function(suggestions, exactMatches, moreResultsAvailable) {
view._pendingOperationsCount--;
if (view._pendingOperationsCount === 0) {
$loading.addClass('hidden');
@@ -401,10 +417,7 @@
// show a notice that the list is truncated
// this is the case if one of the search results is at least as long as the max result config option
if(oc_config['sharing.maxAutocompleteResults'] > 0 &&
Math.min(perPage, oc_config['sharing.maxAutocompleteResults'])
<= Math.max(users.length, groups.length, remotes.length, emails.length, lookup.length)) {
if(moreResultsAvailable) {
var message = t('core', 'This list is maybe truncated - please refine your search term to see more results.');
$('.ui-autocomplete').append('<li class="autocomplete-note">' + message + '</li>');
}
@@ -557,7 +570,7 @@
$shareWithField.focus();
};
var perPage = 200;
var perPage = parseInt(oc_config['sharing.maxAutocompleteResults'], 10) || 200;
var onlyExactMatches = true;
this._getSuggestions(
$shareWithField.val(),
+203 -63
View File
@@ -22,6 +22,7 @@
/* global oc_appconfig, sinon */
describe('OC.Share.ShareDialogView', function() {
var $container;
var oldConfig;
var oldAppConfig;
var autocompleteStub;
var avatarStub;
@@ -40,6 +41,9 @@ describe('OC.Share.ShareDialogView', function() {
// horrible parameters
$('#testArea').append('<input id="allowShareWithLink" type="hidden" value="yes">');
$container = $('#shareContainer');
oldConfig = window.oc_config;
window.oc_config = window.oc_config || {};
window.oc_config['sharing.maxAutocompleteResults'] = 0;
/* jshint camelcase:false */
oldAppConfig = _.extend({}, oc_appconfig.core);
oc_appconfig.core.enforcePasswordForPublicLink = false;
@@ -108,6 +112,7 @@ describe('OC.Share.ShareDialogView', function() {
});
afterEach(function() {
OC.currentUser = oldCurrentUser;
window.oc_config = oldConfig;
/* jshint camelcase:false */
oc_appconfig.core = oldAppConfig;
@@ -357,9 +362,10 @@ describe('OC.Share.ShareDialogView', function() {
);
expect(doneStub.calledOnce).toEqual(true);
expect(doneStub.calledWithExactly([], [])).toEqual(true);
expect(doneStub.calledWithExactly([], [], false)).toEqual(true);
expect(failStub.called).toEqual(false);
});
it('single partial match', function() {
var doneStub = sinon.stub();
var failStub = sinon.stub();
@@ -407,11 +413,14 @@ describe('OC.Share.ShareDialogView', function() {
);
expect(doneStub.calledOnce).toEqual(true);
expect(doneStub.calledWithExactly([{
'label': 'bobby',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'imbob'}
}], [
])).toEqual(true);
expect(doneStub.calledWithExactly(
[{
'label': 'bobby',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'imbob'}
}],
[],
false
)).toEqual(true);
expect(failStub.called).toEqual(false);
});
it('single exact match', function() {
@@ -461,13 +470,17 @@ describe('OC.Share.ShareDialogView', function() {
);
expect(doneStub.calledOnce).toEqual(true);
expect(doneStub.calledWithExactly([{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}], [{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}])).toEqual(true);
expect(doneStub.calledWithExactly(
[{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}],
[{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}],
false
)).toEqual(true);
expect(failStub.called).toEqual(false);
});
it('mixed matches', function() {
@@ -548,28 +561,140 @@ describe('OC.Share.ShareDialogView', function() {
);
expect(doneStub.calledOnce).toEqual(true);
expect(doneStub.calledWithExactly([{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}, {
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_GROUP, 'shareWith': 'group1'}
}, {
'label': 'bobby',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'imbob'}
}, {
'label': 'bob the second',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user2'}
}, {
'label': 'bobfans',
'value': {'shareType': OC.Share.SHARE_TYPE_GROUP, 'shareWith': 'fans'}
}], [{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}, {
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_GROUP, 'shareWith': 'group1'}
}])).toEqual(true);
expect(doneStub.calledWithExactly(
[{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}, {
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_GROUP, 'shareWith': 'group1'}
}, {
'label': 'bobby',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'imbob'}
}, {
'label': 'bob the second',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user2'}
}, {
'label': 'bobfans',
'value': {'shareType': OC.Share.SHARE_TYPE_GROUP, 'shareWith': 'fans'}
}],
[{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}, {
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_GROUP, 'shareWith': 'group1'}
}],
false
)).toEqual(true);
expect(failStub.called).toEqual(false);
});
it('capped mixed matches', function() {
window.oc_config['sharing.maxAutocompleteResults'] = 3;
var doneStub = sinon.stub();
var failStub = sinon.stub();
dialog._getSuggestions('bob', 42, shareModel).done(doneStub).fail(failStub);
var jsonData = JSON.stringify({
'ocs': {
'meta': {
'status': 'success',
'statuscode': 100,
'message': null
},
'data': {
'exact': {
'users': [
{
'label': 'bob',
'value': {
'shareType': OC.Share.SHARE_TYPE_USER,
'shareWith': 'user1'
}
}
],
'groups': [
{
'label': 'bob',
'value': {
'shareType': OC.Share.SHARE_TYPE_GROUP,
'shareWith': 'group1'
}
}
],
'remotes': [],
'remote_groups': [],
},
'users': [
{
'label': 'bobby',
'value': {
'shareType': OC.Share.SHARE_TYPE_USER,
'shareWith': 'imbob'
}
},
{
'label': 'bob the second',
'value': {
'shareType': OC.Share.SHARE_TYPE_USER,
'shareWith': 'user2'
}
}
],
'groups': [
{
'label': 'bobfans',
'value': {
'shareType': OC.Share.SHARE_TYPE_GROUP,
'shareWith': 'fans'
}
}
],
'remotes': [],
'remote_groups': [],
'lookup': []
}
}
});
expect(doneStub.called).toEqual(false);
expect(failStub.called).toEqual(false);
fakeServer.requests[0].respond(
200,
{'Content-Type': 'application/json'},
jsonData
);
expect(doneStub.calledOnce).toEqual(true);
expect(doneStub.calledWithExactly(
[{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}, {
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_GROUP, 'shareWith': 'group1'}
}, {
'label': 'bobby',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'imbob'}
}, {
'label': 'bob the second',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user2'}
}, {
'label': 'bobfans',
'value': {'shareType': OC.Share.SHARE_TYPE_GROUP, 'shareWith': 'fans'}
}],
[{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}, {
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_GROUP, 'shareWith': 'group1'}
}],
true
)).toEqual(true);
expect(failStub.called).toEqual(false);
});
@@ -620,13 +745,16 @@ describe('OC.Share.ShareDialogView', function() {
);
expect(doneStub.calledOnce).toEqual(true);
expect(doneStub.calledWithExactly([{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}], [{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}])).toEqual(true);
expect(doneStub.calledWithExactly(
[{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}], [{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}],
false
)).toEqual(true);
expect(failStub.called).toEqual(false);
var done2Stub = sinon.stub();
@@ -638,13 +766,17 @@ describe('OC.Share.ShareDialogView', function() {
expect(failStub.called).toEqual(false);
expect(done2Stub.calledOnce).toEqual(true);
expect(done2Stub.calledWithExactly([{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}], [{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}])).toEqual(true);
expect(done2Stub.calledWithExactly(
[{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}],
[{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}],
false
)).toEqual(true);
expect(fail2Stub.called).toEqual(false);
});
@@ -695,13 +827,17 @@ describe('OC.Share.ShareDialogView', function() {
);
expect(doneStub.calledOnce).toEqual(true);
expect(doneStub.calledWithExactly([{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}], [{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}])).toEqual(true);
expect(doneStub.calledWithExactly(
[{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}],
[{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}],
false
)).toEqual(true);
expect(failStub.called).toEqual(false);
var done2Stub = sinon.stub();
@@ -741,13 +877,17 @@ describe('OC.Share.ShareDialogView', function() {
expect(fail2Stub.called).toEqual(false);
expect(done3Stub.calledOnce).toEqual(true);
expect(done3Stub.calledWithExactly([{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}], [{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}])).toEqual(true);
expect(done3Stub.calledWithExactly(
[{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}],
[{
'label': 'bob',
'value': {'shareType': OC.Share.SHARE_TYPE_USER, 'shareWith': 'user1'}
}],
false
)).toEqual(true);
expect(fail3Stub.called).toEqual(false);
});
});
+1 -3
View File
@@ -441,7 +441,7 @@ class OC {
// session timeout
if ($session->exists('LAST_ACTIVITY') && (time() - $session->get('LAST_ACTIVITY') > $sessionLifeTime)) {
if (isset($_COOKIE[session_name()])) {
setcookie(session_name(), null, -1, self::$WEBROOT ? : '/');
setcookie(session_name(), '', -1, self::$WEBROOT ? : '/');
}
\OC::$server->getUserSession()->logout();
}
@@ -895,8 +895,6 @@ class OC {
self::$loader->setMemoryCache($memcacheFactory->createLocal('Autoloader'));
} catch (\Exception $ex) {
}
self::$composerAutoloader->setApcuPrefix($instanceId . '-mainComposer');
}
}
@@ -184,7 +184,7 @@ class DefaultTokenProvider implements IProvider {
throw new InvalidTokenException();
}
if ($token->getExpires() !== null && $token->getExpires() < $this->time->getTime()) {
if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
throw new ExpiredTokenException($token);
}
@@ -80,7 +80,7 @@ class PublicKeyTokenProvider implements IProvider {
throw new InvalidTokenException();
}
if ($token->getExpires() !== null && $token->getExpires() < $this->time->getTime()) {
if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
throw new ExpiredTokenException($token);
}
@@ -94,7 +94,7 @@ class PublicKeyTokenProvider implements IProvider {
throw new InvalidTokenException();
}
if ($token->getExpires() !== null && $token->getExpires() < $this->time->getTime()) {
if ((int)$token->getExpires() !== 0 && $token->getExpires() < $this->time->getTime()) {
throw new ExpiredTokenException($token);
}
+19
View File
@@ -244,6 +244,25 @@ class Factory implements IFactory {
return 'en_US';
}
/**
* find the matching lang from the locale
*
* @param string $app
* @param string $locale
* @return null|string
*/
public function findLanguageFromLocale(string $app = 'core', string $locale = null) {
if ($this->languageExists($app, $locale)) {
return $locale;
}
// Try to split e.g: fr_FR => fr
$locale = explode('_', $locale)[0];
if ($this->languageExists($app, $locale)) {
return $locale;
}
}
/**
* Find all available languages for an app
*
+1 -1
View File
@@ -54,7 +54,7 @@ class Internal extends Session {
try {
$this->invoke('session_start');
} catch (\Exception $e) {
setcookie($this->invoke('session_name'), null, -1, \OC::$WEBROOT ?: '/');
setcookie($this->invoke('session_name'), '', -1, \OC::$WEBROOT ?: '/');
}
restore_error_handler();
if (!isset($_SESSION)) {
+1 -1
View File
@@ -47,7 +47,7 @@ class IconsCacher {
protected $urlGenerator;
/** @var string */
private $iconVarRE = '/--(icon-[a-zA-Z0-9-]+): url\(["\']([a-zA-Z0-9-_\~\/\.\?\=]+)[^;]+;/m';
private $iconVarRE = '/--(icon-[a-zA-Z0-9-]+):\s?url\(["\']([a-zA-Z0-9-_\~\/\.\?\=]+)[^;]+;/m';
/** @var string */
private $fileName = 'icons-vars.css';
+5 -2
View File
@@ -139,9 +139,12 @@ class TemplateLayout extends \OC_Template {
}
// Send the language and the locale to our layouts
$lang = \OC::$server->getL10NFactory()->findLanguage();
$locale = \OC::$server->getL10NFactory()->findLocale($lang);
$localeLang = \OC::$server->getL10NFactory()->findLanguageFromLocale('lib', $locale);
$lang = str_replace('_', '-', $lang);
$this->assign('language', $lang);
$this->assign('locale', \OC::$server->getL10NFactory()->findLocale($lang));
$this->assign('locale', $locale);
if(\OC::$server->getSystemConfig()->getValue('installed', false)) {
if (empty(self::$versionHash)) {
@@ -159,7 +162,7 @@ class TemplateLayout extends \OC_Template {
if ($this->config->getSystemValue('installed', false) && $renderAs != 'error') {
if (\OC::$server->getContentSecurityPolicyNonceManager()->browserSupportsCspV3()) {
$jsConfigHelper = new JSConfigHelper(
\OC::$server->getL10N('lib'),
\OC::$server->getL10N('lib', $localeLang ?: $lang),
\OC::$server->query(Defaults::class),
\OC::$server->getAppManager(),
\OC::$server->getSession(),
@@ -67,7 +67,7 @@ interface ICloudFederationProviderManager {
*
* @param string $resourceType
* @return ICloudFederationProvider
* @throws Exceptions\ProviderDoesNotExistsException;
* @throws Exceptions\ProviderDoesNotExistsException
*
* @since 14.0.0
*/
+10
View File
@@ -53,6 +53,16 @@ interface IFactory {
*/
public function findLocale($lang = null);
/**
* find the matching lang from the locale
*
* @param string $app
* @param string $locale
* @return null|string
* @since 14.0.1
*/
public function findLanguageFromLocale(string $app = 'core', string $locale = null);
/**
* Find all available languages for an app
*
+4 -4
View File
@@ -543,7 +543,7 @@ Raw output
* @return array
*/
protected function getAppDirsWithDifferentOwner(): array {
$currentUser = posix_getpwuid(posix_getuid());
$currentUser = posix_getuid();
$appDirsWithDifferentOwner = [[]];
foreach (OC::$APPSROOTS as $appRoot) {
@@ -561,11 +561,11 @@ Raw output
/**
* Tests if the directories for one apps directory are writable by the current user.
*
* @param array $currentUser The current user
* @param int $currentUser The current user
* @param array $appRoot The app root config
* @return string[] The none writable directory paths inside the app root
*/
private function getAppDirsWithDifferentOwnerForAppRoot(array $currentUser, array $appRoot): array {
private function getAppDirsWithDifferentOwnerForAppRoot(int $currentUser, array $appRoot): array {
$appDirsWithDifferentOwner = [];
$appsPath = $appRoot['path'];
$appsDir = new DirectoryIterator($appRoot['path']);
@@ -573,7 +573,7 @@ Raw output
foreach ($appsDir as $fileInfo) {
if ($fileInfo->isDir() && !$fileInfo->isDot()) {
$absAppPath = $appsPath . DIRECTORY_SEPARATOR . $fileInfo->getFilename();
$appDirUser = posix_getpwuid(fileowner($absAppPath));
$appDirUser = fileowner($absAppPath);
if ($appDirUser !== $currentUser) {
$appDirsWithDifferentOwner[] = $absAppPath;
}
@@ -59,7 +59,7 @@
</div>
<div class="section">
<div id="version" class="section">
<!-- should be the last part, so Updater can follow if enabled (it has no heading therefore). -->
<h2><?php p($l->t('Version'));?></h2>
<p><strong><a href="<?php print_unescaped($theme->getBaseUrl()); ?>" rel="noreferrer noopener" target="_blank"><?php p($theme->getTitle()); ?></a> <?php p(OC_Util::getHumanVersion()) ?></strong></p>
+2
View File
@@ -206,6 +206,8 @@ su --shell /bin/bash --login www-data --command "cd $NEXTCLOUD_DIR && $ACCEPTANC
echo "Saving the default state so acceptance tests can reset to it"
find . -name ".gitignore" -exec rm --force {} \;
# Create dummy files in empty directories to force Git to save the directories.
find . -not -path "*.git*" -type d -empty -exec touch {}/.keep \;
git add --all && echo 'Default state' | git -c user.name='John Doe' -c user.email='john@doe.org' commit --quiet --file=-
cd tests/acceptance
+27
View File
@@ -171,4 +171,31 @@ class L10nTest extends TestCase {
$l = \OC::$server->getL10N('lib', 'de');
$this->assertEquals('Mo.', $l->l('weekdayName', new \DateTime('2017-11-6'), ['width' => 'abbreviated']));
}
/**
* @dataProvider findLanguageFromLocaleData
* @param $locale
* @param $language
*/
public function testFindLanguageFromLocale($locale, $language) {
$this->assertEquals(
$language,
\OC::$server->getL10NFactory()->findLanguageFromLocale('lib', $locale)
);
}
/**
* @return array
*/
public function findLanguageFromLocaleData(): array {
return [
'en_US' => ['en_US', 'en'],
'en_UK' => ['en_UK', 'en'],
'de_DE' => ['de_DE', 'de_DE'],
'de_AT' => ['de_AT', 'de'],
'es_EC' => ['es_EC', 'es_EC'],
'fi_FI' => ['fi_FI', 'fi'],
'zh_CN' => ['zh_CN', 'zh_CN'],
];
}
}
+2 -2
View File
@@ -29,10 +29,10 @@
// between betas, final and RCs. This is _not_ the public version number. Reset minor/patchlevel
// when updating major/minor version number.
$OC_Version = array(14, 0, 0, 18);
$OC_Version = array(14, 0, 1, 1);
// The human readable string
$OC_VersionString = '14.0.0 RC 2';
$OC_VersionString = '14.0.1';
$OC_VersionCanBeUpgradedFrom = [
'nextcloud' => [