Compare commits

..

302 Commits

Author SHA1 Message Date
Morris Jobke c2cea293d5 Merge pull request #8807 from nextcloud/final-13.0.1
[stable13] 13.0.1
2018-03-13 19:46:51 +01:00
Morris Jobke ef2de71988 13.0.1
Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-03-13 18:22:12 +01:00
Nextcloud bot f66af48d49 [tx-robot] updated from transifex 2018-03-13 01:12:30 +00:00
Nextcloud bot 93f5745700 [tx-robot] updated from transifex 2018-03-12 01:12:46 +00:00
Nextcloud bot 8e27fed9d3 [tx-robot] updated from transifex 2018-03-11 01:12:36 +00:00
Nextcloud bot 8e8368ae0b [tx-robot] updated from transifex 2018-03-10 01:12:24 +00:00
Morris Jobke 8d165d63ed Merge pull request #8748 from nextcloud/13.0.1-RC1
13.0.1 RC1
2018-03-09 21:22:14 +01:00
Morris Jobke d1e600773c 13.0.1 RC1
Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-03-09 16:19:00 +01:00
Morris Jobke b0f0c26fe3 Merge pull request #8745 from nextcloud/stable13-8716
[13] Remove base url from global cache prefix
2018-03-09 16:15:48 +01:00
Morris Jobke 17f75d6797 Mock method of actual cache
Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-03-09 15:36:53 +01:00
Morris Jobke f17cabd63e Merge pull request #8758 from nextcloud/stable13-8594-add-acceptance-tests-for-permissions-on-public-shared-folders
[stable13] Add acceptance tests for permissions on public shared folders
2018-03-09 15:23:09 +01:00
Roeland Jago Douma 43243380f1 Always return the depscache
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-03-09 14:43:54 +01:00
Nextcloud bot f22bae3546 [tx-robot] updated from transifex 2018-03-09 13:31:55 +00:00
Daniel Calviño Sánchez e9f5073677 Add acceptance tests for creation of subfolders in public shared folders
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-09 12:26:58 +01:00
Daniel Calviño Sánchez 4337de7559 Extract common "wait for" functions to a helper class
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-09 12:26:58 +01:00
Daniel Calviño Sánchez 05fd72937b Generalize file list steps so a specific ancestor can be used
The "FileListContext" provides steps to interact with and check the
behaviour of a file list. However, the "FileListContext" does not know
the right file list ancestor that has to be used by the file list steps,
so until now the file list steps were explicitly wired to the Files app
and they could be used only in that case.

Instead of duplicating the steps with a slightly different name (for
example, "I create a new folder named :folderName in the public shared
folder" instead of "I create a new folder named :folderName") the steps
were generalized; now contexts that "know" that certain file list
ancestor has to be used by the FileListContext steps performed by
certain actor from that point on (until changed again) set it
explicitly. For example, when the current page is the Files app then the
ancestor of the file list is the main view of the current section of the
Files app, but when the current page is a shared link then the ancestor
is set to null (because there will be just one file list, and thus its
ancestor is not relevant to differentiate between instances)

A helper trait, "FileListAncestorSetter", was introduced to reduce the
boilerplate needed to set the file list ancestor from other contexts.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-09 12:26:58 +01:00
Daniel Calviño Sánchez 7ebbd666a8 Generalize file list locators so a specific ancestor can be used
The file list is used in other places besides the Files app (for
example, the File sharing app); in those cases the locators for the file
list elements are the same, but not for the ancestor of the file list.
To make possible to reuse the file list locators in those cases too now
they receive the ancestor to use.

Note that the locators for the file actions menu were not using an
ancestor locator because it is expected that there is only one file
actions menu at a time in the whole page; that may change in the future,
but for the time being it is a valid assumption and thus the ancestor
was not added to those locators in this commit.

Although the locators were generalized the steps themselves still use
the "FilesAppContext::currentSectionMainView" locator as ancestor; the
steps will be generalized in a following commit.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-09 12:26:58 +01:00
Daniel Calviño Sánchez 0709f4fd67 Store the name of the actor in the Actor object
This is needed to be able to easily use the actor as a key in an array.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-09 12:26:58 +01:00
Daniel Calviño Sánchez da6743277b Extract file list locators and steps to its own class
Besides the extraction some minor adjustments (sorting locators for file
action menu entries to reflect the order of the menu entries in the UI,
moving parametrized locators like "createMenuItemFor" above the locators
that use them and placing "descendantOf" calls always in a new line)
were made too.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-09 12:26:58 +01:00
Roeland Jago Douma 56a4c9d68e Merge pull request #8755 from nextcloud/backport/8747/apps-are-updated
[stable13] Revert wording back to updates
2018-03-09 12:12:29 +01:00
Morris Jobke 6176296c80 Merge pull request #8749 from nextcloud/backport/8596/sharee-email-matches-not-limited
[stable13] Sharee email matches not limited
2018-03-09 11:29:15 +01:00
Joas Schilling 92793e9d92 Revert wording back to updates
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-03-09 11:25:25 +01:00
Morris Jobke 0f1567d8fa Merge pull request #8752 from nextcloud/13-8112
[stable13] Fix integer overflow in ChunkingPlugin
2018-03-09 11:23:28 +01:00
Julius Härtl e2728aaf38 Merge pull request #8746 from nextcloud/8705_13
[stable13] Check if the cached js file exists
2018-03-09 10:37:15 +01:00
Morris Jobke 4fa0cac17c Merge pull request #8725 from nextcloud/objectstore-no-part-files-13
[13]  disable part files for object stores
2018-03-09 10:34:33 +01:00
Morris Jobke ba7cc279e6 Fix integer overflow in ChunkingPlugin
Avoids errors when the size exceeds MAX_INT because of the cast to int. Better cast it to float to avoid this.

Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-03-09 10:27:41 +01:00
Joas Schilling a2f3f0a681 Fix calculation if there are more results
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-03-09 10:16:42 +01:00
Joas Schilling a31439e89d Add tests for finding own email and user results pagination
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-03-09 10:16:12 +01:00
Joas Schilling 932fcc9859 Add the users result only when non empty so tests stay the same
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-03-09 10:15:25 +01:00
Joas Schilling 5b6590f1e9 Also array_slice wide email matches of local users
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-03-09 10:15:04 +01:00
Roeland Jago Douma 85ba5adb33 Fix tests
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-03-09 09:44:36 +01:00
Roeland Jago Douma 2d7d8ca125 Check if the cached js file exists
Fixes #8705

If the file does not exist (for whatever reason). It is never cached. No
matter what the depscache etc tell you.

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-03-09 09:44:32 +01:00
Julius Härtl 88e9542d12 Use cache prefix for theming as well
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-03-09 09:24:52 +01:00
Julius Härtl d4d3cecbf8 Fix tests to use ICacheFactory
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-03-09 09:24:50 +01:00
Julius Härtl b14e4ec6a6 Actually clear cache values for all base urls
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-03-09 09:24:07 +01:00
Julius Härtl a098b57817 Use JSCombiner from server container when searching for JS files
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-03-09 09:24:07 +01:00
Julius Härtl c4539c34c9 Move base url from global cache prefix to frontend related ones
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-03-09 09:24:06 +01:00
Roeland Jago Douma d1547ee3b0 Merge pull request #8738 from nextcloud/stable13-8728-better-handling-of-invisible-elements-in-acceptance-tests
[stable13] Better handling of invisible elements in acceptance tests
2018-03-09 08:31:49 +01:00
Daniel Calviño Sánchez fc6c290a4f Add automatic handling of NoSuchElement exceptions
NoSuchElement exceptions are sometimes thrown instead of
StaleElementReference exceptions. This can happen when the Selenium2
driver for Mink performs an action on an element through the WebDriver
session instead of directly through the WebDriver element. In that case,
if the element with the given ID does not exist, a NoSuchElement
exception would be thrown instead of a StaleElementReference exception,
so those cases are handled like StaleElementReference exceptions.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-09 02:17:04 +01:00
Daniel Calviño Sánchez f0cbeecf21 Add automatic handling of MoveTargetOutOfBounds exceptions
MoveTargetOutOfBounds exceptions are sometimes thrown instead of
ElementNotVisible exceptions. This can happen when the Selenium2 driver
for Mink moves the cursor on an element using the "moveto" method of the
Webdriver session, for example, before clicking on an element. In that
case, if the element is not visible, "moveto" would throw a
MoveTargetOutOfBounds exception instead of an ElementNotVisible
exception, so those cases are handled like ElementNotVisible exceptions.

Note that MoveTargetOutOfBounds exceptions could be thrown too if the
element was visible but "out of reach"; there is no problem in handling
those cases as if the element was not visible, as the exception will be
thrown again anyway once it is verified that the element is indeed
visible.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-09 02:17:04 +01:00
Nextcloud bot b593fd1406 [tx-robot] updated from transifex 2018-03-09 01:12:37 +00:00
Robin Appelman 9342f97a28 emit pre-hooks earlier when not using part files
Signed-off-by: Robin Appelman <robin@icewind.nl>
2018-03-08 13:09:09 +01:00
Robin Appelman a95ccf4248 disable part files for object stores
Signed-off-by: Robin Appelman <robin@icewind.nl>
2018-03-08 13:09:02 +01:00
Roeland Jago Douma d7a70aba84 Merge pull request #8686 from nextcloud/backport/8298/fix-activities-for-end2end-encryption
[stable13] Fix activities for end2end encryption
2018-03-06 22:44:54 +01:00
Roeland Jago Douma 41f8f68a5a Merge pull request #8693 from nextcloud/13-8173
[stable13] Fix undefined index problem
2018-03-06 19:27:30 +01:00
michaelletzgus 7e651ffd54 Fix undefined index problem
Nextcloud 13RC4, error in logfile, triggered by "occ config:list":

Invalid argument supplied for foreach() at lib/private/AppConfig.php#297
PHP	Undefined index: workflowengine at lib/private/AppConfig.php#297

Fix: Check if index exists in array before using it.
2018-03-06 18:37:52 +01:00
Roeland Jago Douma a637e0d686 Merge pull request #8687 from nextcloud/backport/8328/filter-out-the-current-user-by-email-too
[stable13] Filter out the current user when searching for emails too
2018-03-06 17:11:49 +01:00
Roeland Jago Douma 56d5eb17fe Merge pull request #8688 from nextcloud/13-8557
[stable13] Fix check if theming defaults instance is available
2018-03-06 17:11:37 +01:00
Joas Schilling 173388dcd4 PHP 5.6 compatibility
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-03-06 14:05:14 +01:00
Morris Jobke 1bdf4f55cb Merge pull request #8685 from nextcloud/backport/8664/add-missing-settings-page-title-again
[stable13] Set the correct active navigation entry
2018-03-06 13:57:25 +01:00
Morris Jobke 47fa0988d9 Merge pull request #8683 from nextcloud/8474_13
[stable13] Log exceptions that happen when writing the app store reply to storage
2018-03-06 13:39:49 +01:00
Morris Jobke ed8e4cc785 Merge pull request #8667 from nextcloud/8158_13
[stable13] Use a more widely available method to test s3 settings
2018-03-06 13:38:23 +01:00
Morris Jobke 16fa18ab49 Merge pull request #8678 from nextcloud/7707_13
[stable13] generate different UIDs for Birthday, Anniversary and Death event
2018-03-06 13:37:21 +01:00
Morris Jobke eefbcb32ed Fix check if theming defaults instance is available
The check in URLGenerator.php#169 and Server.php#945 are different and thus the DI container could return a \OC_Defaults object which does not provide the wanted method caising a PHP error.

Fixes #8420

Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-03-06 13:24:18 +01:00
Morris Jobke 5f8c773b27 Merge pull request #8680 from nextcloud/8391_13
[stable13] Don't use double quotes in MySQL queries
2018-03-06 13:18:59 +01:00
Joas Schilling 18968e84fc Filter out the current user when searching for emails too
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-03-06 12:20:24 +01:00
Joas Schilling d16aa27516 Fix unit test
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-03-06 12:16:12 +01:00
Joas Schilling 8f8d7cf9d3 Catch exception when the parent is deleted as well
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-03-06 12:16:04 +01:00
Joas Schilling 5d8aaf9696 Do a recursion instead of an endless loop
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-03-06 12:15:57 +01:00
Joas Schilling 7c15b99a49 Fix problem with deleted files
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-03-06 12:15:51 +01:00
Joas Schilling f1e01dbbbc Fix path handling for activities
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-03-06 12:15:45 +01:00
Joas Schilling 737af44b63 Add special handling for e2e encryption
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-03-06 12:15:36 +01:00
Joas Schilling 0911f3bde1 Extract duplicated logic into a method
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-03-06 12:15:13 +01:00
Joas Schilling e11dab4047 Set the correct active navigation entry
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-03-06 12:05:19 +01:00
Roeland Jago Douma 242f0c0b5a Merge pull request #8676 from nextcloud/8297_13
[stable13] Fix example regex for user agent matching
2018-03-06 11:54:27 +01:00
Morris Jobke 0667a32c83 Merge pull request #8673 from nextcloud/stable13-8634
[stable13] do not create empty userid when attribute does not have allowed chars
2018-03-06 11:30:48 +01:00
Joas Schilling de1f223961 Log exceptions that happen when writing the app store reply to storage
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-03-06 11:29:05 +01:00
Robin Müller 619ee56835 Don't use double quotes in MySQL queries
MySQL databases with the ANSI_QUOTES mode enabled treat " as an identifier
quote (see https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_ansi_quotes).
So for such databases the 'occ upgrade' fails with an error message like this:
... unknown column 'oc_*' in where clause.

This fix replaces the doulbe quotes with single quotes that should be always
used in MySQL queries to quote literal strings.

Signed-off-by: Robin Müller <robin.mueller@1und1.de>
2018-03-06 11:25:07 +01:00
Georg Ehrke 6171940717 generate different UIDs for Birthday, Anniversary and Death event
Signed-off-by: Georg Ehrke <developer@georgehrke.com>
2018-03-06 11:20:53 +01:00
Joas Schilling 02af9b2f6f Fix example regex for user agent matching
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-03-06 11:16:41 +01:00
Roeland Jago Douma ff7237a098 Merge pull request #8668 from nextcloud/8217_13
[stable13] Use proper lanugage in langauge code
2018-03-06 09:47:20 +01:00
Roeland Jago Douma f4aae102f7 Merge pull request #8675 from nextcloud/stable13-8601
[13] Remove too restrict check for background image/color
2018-03-06 09:46:52 +01:00
Julius Härtl 80842e1611 Remove to restrict check for background image/color
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-03-06 09:08:49 +01:00
Nextcloud bot d3d0d9e11d [tx-robot] updated from transifex 2018-03-06 01:12:41 +00:00
blizzz 0045e823fe Merge pull request #8669 from nextcloud/8218_13
[stable13] Display the proper language strings in setttings
2018-03-05 23:46:26 +01:00
Arthur Schiwon 6e3c05f513 do not create empty userid when attribute does not have allowed chars
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
2018-03-05 23:14:36 +01:00
Roeland Jago Douma 19ded76b77 Display the proper language strings in setttings
Since this was moved to lib, we have to the lib language files.

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-03-05 19:48:16 +01:00
Roeland Jago Douma 34671d6ad4 Use proper lanugage in langauge code
Fixes #8180

The _ is not valid in language codes use - instead.

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-03-05 19:44:54 +01:00
Robin Appelman 3036fb95ae Use a more widely available method to test s3 settings
Signed-off-by: Robin Appelman <robin@icewind.nl>
2018-03-05 19:41:56 +01:00
Roeland Jago Douma 655e39ffcd Merge pull request #8610 from nextcloud/stable13-8588-fix-breadcrumbs-width-calculation
[stable13] Fix breadcrumbs width calculation
2018-03-05 19:37:53 +01:00
Roeland Jago Douma 07aba8cdac Merge pull request #8663 from nextcloud/fix-ie11-datepicker-display-backport
[stable13] Fixed date/time picker on IE11
2018-03-05 19:35:25 +01:00
John Molakvoæ (skjnldsv) 1b0416b1a1 Fixed date/time picker on IE11
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
2018-03-05 16:40:44 +01:00
Roeland Jago Douma 9432c59db4 Merge pull request #8654 from nextcloud/stable13-8630
[stable13] use hash algo that's robust against collisions
2018-03-05 14:48:49 +01:00
Arthur Schiwon 962b046ab5 use hash algo that's robust against collisions
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
2018-03-05 13:20:22 +01:00
Joas Schilling 6104a7043e Merge pull request #8636 from nextcloud/8289_13
[stable13] AppData hardening
2018-03-05 12:38:43 +01:00
Joas Schilling 479b9465c0 Merge pull request #8631 from nextcloud/stable13-8372
[13] Properly encapsulate require_once for app.php
2018-03-05 12:35:50 +01:00
Nextcloud bot d74bad2dc1 [tx-robot] updated from transifex 2018-03-05 01:12:36 +00:00
Nextcloud bot 7717dbbe30 [tx-robot] updated from transifex 2018-03-04 01:13:07 +00:00
Nextcloud bot e23f06561a [tx-robot] updated from transifex 2018-03-03 01:12:39 +00:00
Roeland Jago Douma 46bb3fee81 Merge pull request #8609 from nextcloud/ie11-nav-flex-fix
[stable13] Fixed app navigation for IE11
2018-03-02 21:27:20 +01:00
Roeland Jago Douma 9413f97b92 Hardening of SimpleFile getContent
if file_get_contents fails remove the file. And traverse up the tree
checking if the other folders are there.

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-03-02 21:23:41 +01:00
Julius Härtl 9f7e05e737 Add throws annotation
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-03-02 17:16:36 +01:00
Julius Härtl a61608e8c7 Properly encapsulate require_once for app.php
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-03-02 17:16:36 +01:00
Joas Schilling 364e7fe1be Merge pull request #8621 from nextcloud/13-8612
[stable13] Update commentstabview.js
2018-03-02 11:24:22 +01:00
rakekniven cbba3e2432 Update commentstabview.js
Changed typo reported at GitHub.
See https://www.transifex.com/nextcloud/nextcloud/translate/#de_DE/$/91002505?issue=yes

Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-03-02 10:41:26 +01:00
Morris Jobke 59d6f45c41 Merge pull request #8615 from nextcloud/stable13-8355
[stable13] Fix comments (and systemtags) when involving users with numerical ids
2018-03-02 10:35:40 +01:00
Nextcloud bot 369b3b28c7 [tx-robot] updated from transifex 2018-03-02 01:12:43 +00:00
Arthur Schiwon 7bd1aac209 backport of #8355 to stable13
test creating comments with numeric user ids

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

fix creating comments when file is accessible to users with numeric ids

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

tests for systemtags related to numeric user ids

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

fix systemtags event with numeric user ids

Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
2018-03-02 00:28:20 +01:00
Daniel Calviño Sánchez 22f9d0519a Update comments in tests
Menu and home are not always visible; home is always visible, but menu
is shown only when needed.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-01 20:33:14 +01:00
Daniel Calviño Sánchez 21551d7884 Improve documentation of "getTotalWidth"
"getTotalWidth" is not more accurate; it is simply not clamped.
Moreover, "width/outerWidth" could be used in tests too, and also even
if "getTotalWidth" could be used in tests while others not that would
not be something to be stated in the API documentation, but in a
comment.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-01 20:33:14 +01:00
Daniel Calviño Sánchez 23559b2eda Do not show the crumbs again after hiding them
After the changes in the previous commit "_showCrumb" no longer shows
the menu, only the same crumb that was hidden by the last call to
"_hideCrumb". Therefore, if the crumb was hidden because it did not fit
there is no need to try to show it again, as it will still not fit.

Moreover, the calculated width for a hidden element is not always
accurate; in some cases the calculated width is lower than the actual
width (it happens, for example, when using a background image like the
"Share" icon), which causea the crumb to be shown even if there is not
enough room, which in the end causes the siblings to overflow the
contents.

No unit tests for this one, though; you will have to trust me on this,
sorry ;-)

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-01 20:33:14 +01:00
Daniel Calviño Sánchez a1af18fa35 Fix menu visibility
The crumb for the menu was shown like any other crumb when calling
"_showCrumb", but it was also shown when other crumbs were hidden
without taking into account the available width. This caused several
related problems, like the breadcrumbs taking too much space when the
menu was sometimes shown after the rest of the crumbs were adjusted to
the available width, or the menu being shown instead of the last crumb
even if there was room for it when the available width was increased.

Now the menu is always hidden before starting the resizing of the crumbs
to ensure that whether it was previously shown or not does not affect
the result. In a similar way, the menu will no longer be shown by
"_showCrumb", as it is not a regular crumb that has to be shown simply
if there is enough room. The menu is now shown as soon as any other
crumb is hidden; this ensures that the menu width will be taken into
account in further width checks. As when _updateMenu" is called it no
longer needs to take care of showing the menu this fixes the issue
revealed when fixing the test setup in the previous commit.

Finally, this implicitly fixes the failure in the breadcrumbs tests when
run on Firefox, as it was caused by the menu interfering in the
calculations of the other crumbs when increasing the width.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-01 20:33:14 +01:00
Daniel Calviño Sánchez e33a9693f7 Fix setup to test the breadcrumbs menu
The "Shows only items not in the breadcrumb" test was failing when run
on Firefox, but not on PhantomJS. This was caused by the differences in
the starting width between both browsers and an incorrect setup of the
test (the width set for the crumbs was overriden when the breadcrumbs
were rendered again, and the breadcrumb was resized to 300 from an
indeterminate initial width).

Now the crumbs are rendered and then its width, padding and margin are
set to a known value. Then it is resized to 1000px, which ensures that
there will be enough room for all the crumbs and thus the menu will be
hidden, and finally it is resized to 300, which causes the middle crumb
to be hidden and the menu to be shown.

Note, however, that the test now always fails, no matter if it is run on
PhantomJS or on Firefox; if the menu crumb is hidden when "_updateMenu"
is called it will show it, but it will also wrongly try to add the menu
itself to the menu. As the "crumb-id" of the menu crumb is "-1" this
causes the last regular crumb to be added to the menu. This will be
fixed with other related issues in the next commit.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-01 20:33:14 +01:00
Daniel Calviño Sánchez 83b50690a8 Take padding and margins of crumbs into account
When calculating the total width of the crumbs only its padding was
taken into account; now the margin is too. In a similar way, before
showing a crumb only its width was taken into account; now its padding
and margin are taken into account too.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-01 20:33:14 +01:00
Daniel Calviño Sánchez 89c0a0733f Use hard-coded values for paddings and margins
This ensures that the resize tests do not depend on the values set in
the CSS files.

Note that this change causes a test to fail with Firefox, but not with
PhantomJS. This is due to a difference in the starting width used by
Firefox and by PhantomJS, and it will be fixed in a following commit.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-01 20:33:14 +01:00
Daniel Calviño Sánchez d9405a2b02 Compress siblings before calculating the available width for crumbs
When the parent element of the breadcrumbs was resized to a larger width
and the siblings of the breadcrumbs expanded to fill all the available
width some crumbs could be hidden even if there was enough room for
them. The reason was that the width of the siblings being used to
calculate the available width for the breadcrumbs was the expanded width
of the siblings. Now as many crumbs as possible (that is, fitting in the
parent, no matter the siblings) are first shown so the expanding
siblings are compressed before calculating the available width.

Due to the lack of support for flexboxes in PhantomJS the related unit
test is skipped; it has to be run in other browser, like Firefox.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-01 20:33:14 +01:00
Daniel Calviño Sánchez a93dac6a9c Take all visible siblings into account
Other apps could add elements to the controls outside the creatable
actions div (for example, the button to switch to the gallery), so the
widths of all the visible siblings of the breadcrumbs have to be taken
into account in the size calculations.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-01 20:33:14 +01:00
Daniel Calviño Sánchez bb85084c3d Take padding and margin of the creatable actions div into account
There are some differences in width handling between the browsers used
to run the tests, most likely due to their support (or lack of) of
certain CSS features: PhantomJS requires "width" to be set (probably
because it does not handle flex displays and treats it like a block, so
"min-width" does not matter in this case), while Firefox requires
"min-width" to be set (otherwise the children of "#controls" could be
compressed due to its use of flex display and the elements would end
with a different width than the one needed for the tests). Due to all
that the width of the breadcrumb siblings must be specified in the tests
using both "width" and "min-width".

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-01 20:33:14 +01:00
Daniel Calviño Sánchez 1da92fd5da Do not render the breadcrumbs again in resize tests
There is no need to call "setDirectory" again in resize tests; it is
enough to simply resize them (and isolates them better to just test the
resizing behaviour).

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-01 20:33:14 +01:00
Daniel Calviño Sánchez 2fd3fa20df Replace attribute with local variable
The "usedWidth" attribute was not used elsewhere outside the "_resize"
method, so it was replaced with a local variable. Moreover, it was also
renamed to a more suitable name ("availableWidth").

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-01 20:33:14 +01:00
Daniel Calviño Sánchez 61bd3631d9 Set the width of the parent element in breadcrumb tests
Setting the width of the parent element of the breadcrumbs and then
explicitly calling "_resize" is enough to test the resizing behaviour.
This makes possible to remove the "setMaxWidth" method and its related
code, which was used only for testing purposes.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-01 20:33:14 +01:00
John Molakvoæ (skjnldsv) bc2032bed7 fixup! Fixed app navigation for IE11
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
2018-03-01 20:22:49 +01:00
John Molakvoæ (skjnldsv) b768040fca Fixed app navigation for IE11
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
2018-03-01 20:22:42 +01:00
Roeland Jago Douma a2672a2ad8 Merge pull request #8561 from nextcloud/ext-strg-warning-fix
[stable13] Ext storage error warning
2018-03-01 19:36:55 +01:00
Morris Jobke 5a20f64300 Merge pull request #8595 from nextcloud/stable13-8589-fix-upload-button-visible-on-read-only-folders
[stable13] Fix upload button visible on read-only folders
2018-03-01 11:56:59 +01:00
Nextcloud bot 03f127f162 [tx-robot] updated from transifex 2018-03-01 01:12:37 +00:00
Daniel Calviño Sánchez 14abe6a9e0 Fix upload button visible on read-only folders
The div that contains the elements related to the creation of new files,
and thus the upload button, is always present in the DOM; it is hidden
or shown based on the folder permissions by adding or removing the
"hidden" CSS class. However, as the other CSS classes for the div are
"actions" and "creatable" and a "display: flex" rule was defined for
".actions.creatable" below the "display: none" rule for
".actions.hidden" the last one took precedence and the div ended being
always visible, even if the "hidden" CSS class was set. Now the rules
for the ".actions.hidden" selector are defined below the rules for the
".actions.creatable" selector and thus the "display: none" rule is
applied as expected.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-03-01 01:52:08 +01:00
Roeland Jago Douma d7e5a660ca Merge pull request #8577 from nextcloud/8576_13
[stable13] Set autocomplete=new-password for mail share password
2018-02-28 21:07:08 +01:00
Roeland Jago Douma 2c6f3c88cf Merge pull request #8099 from nextcloud/7873_13
[stable13] Don't perform CSRF check on OCS routes with Bearer auth
2018-02-28 14:34:20 +01:00
Roeland Jago Douma 338795a03d Set autocomplete=new-password for mail share password
This avoids the browser to do autocompletion on the mail share password
field.

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-02-28 14:01:43 +01:00
Nextcloud bot d33a93c6f9 [tx-robot] updated from transifex 2018-02-28 01:12:57 +00:00
John Molakvoæ (skjnldsv) 30b9c139b6 Updated error message
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
2018-02-27 12:14:34 +01:00
John Molakvoæ (skjnldsv) 6ff85e1dd6 Fixed default urls
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
2018-02-27 12:14:29 +01:00
John Molakvoæ (skjnldsv) 018ff68f45 Show error if no external storage configured
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
2018-02-27 12:14:23 +01:00
Julius Härtl 282b79c4b1 Merge pull request #8554 from kyrofa/backport_13/8462/theming_app_outside_root
[stable13] theming: handle not being in the serverroot
2018-02-27 10:37:46 +01:00
Nextcloud bot 4c52fed779 [tx-robot] updated from transifex 2018-02-27 01:14:50 +00:00
Kyle Fazzari 4ecf31541b theming: handle not being in the serverroot
Currently, the theming app assumes it's in the serverroot. However, with
Nextcloud's flexibility regarding configurable app paths, this is not a
safe assumption to make. If it happens to be an incorrect assumption,
the theming app fails to work.

Instead of relying on the serverroot, just use the path from the
AppManager and utilize relative paths for assets from there.

Fix #8462

Signed-off-by: Kyle Fazzari <kyrofa@ubuntu.com>
2018-02-26 10:24:34 -08:00
Morris Jobke 88ece3f5d7 Merge pull request #8532 from nextcloud/8499-stable13
[stable13]  Avoid fruitless login attempts
2018-02-26 15:10:52 +01:00
Morris Jobke bf2f744bc7 Merge pull request #8536 from nextcloud/8522-stable13
[stable13] Fix retrieval of group members with numerical uids from LDAP
2018-02-26 15:10:26 +01:00
Arthur Schiwon 8acec5309c fix retrieving group members with numerical uids from LDAP
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
2018-02-26 13:33:35 +01:00
Arthur Schiwon b02d3a27ba tests for retrieving group members with numerical uids
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
2018-02-26 13:33:25 +01:00
Arthur Schiwon fb2ebbd232 don't try login with the same name that just failed
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
2018-02-26 10:32:38 +01:00
Arthur Schiwon f015d38a89 track the state of the bind result
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
2018-02-26 10:32:31 +01:00
Roeland Jago Douma 7e424e52a3 Merge pull request #8518 from nextcloud/stable13-8507
Add some whitespace around change.svg icon (stable13)
2018-02-24 16:25:51 +01:00
Roeland Jago Douma 3c3d007068 Merge pull request #8515 from nextcloud/13-8502
[stable13] Show hint in OCS API for user creation
2018-02-24 16:24:58 +01:00
Nextcloud bot 1eb8aee0e6 [tx-robot] updated from transifex 2018-02-24 01:12:42 +00:00
blizzz a4fbe80f73 Merge pull request #8517 from nextcloud/stable13-8416
[stable13] Fix hiding and event propagation issues with the user management popover
2018-02-23 13:01:43 +01:00
Marin Treselj 5d2feda77c Add some whitespace around change.svg icon (stable13)
Signed-off-by: Marin Treselj <marin@pixelipo.com>
2018-02-23 11:11:20 +01:00
Julius Härtl fef3f23492 Fix hiding and event propagation issues with the user management popover
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-02-23 11:10:03 +01:00
Morris Jobke 168f188596 Show hint in OCS API for user creation
* adds a 107 error code together with the hint of the exception
* logs the exception as warning
* fixes #7946

Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-02-23 10:24:26 +01:00
Nextcloud bot a5b73fe761 [tx-robot] updated from transifex 2018-02-23 01:12:43 +00:00
Nextcloud bot 367770adab [tx-robot] updated from transifex 2018-02-22 01:12:53 +00:00
Roeland Jago Douma 27aa0761bc Merge pull request #8470 from nextcloud/13-8468
[stable13] Use mb_* string methods to extract first character for generated avatars
2018-02-21 13:29:28 +01:00
Morris Jobke f1568b96ce Use mb_* string methods to extract first character for generated avatars
This fixes #8451 where the first character is a non-ASCII character. The `$string[0]` notation only extracted one byte and thus resulting in an invalid code. The `mb_strtoupper` method also allows to convert characters independently from the current locale on the server.

See also http://php.net/manual/en/function.mb-strtoupper.php

Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-02-21 12:40:16 +01:00
Nextcloud bot 86be2687fb [tx-robot] updated from transifex 2018-02-21 01:12:33 +00:00
Morris Jobke 58cc34b816 Merge pull request #8267 from nextcloud/8206_13
[stable13] Better result handling of email search
2018-02-20 23:54:16 +01:00
Joas Schilling d63caf5829 Better result handling of email search
1. Local users should not be returned when searching for empty string
2. The limit of the response should be respected

Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-02-20 17:47:54 +01:00
Roeland Jago Douma a3de507b76 Merge pull request #8440 from nextcloud/8428_13
[stable13] Use TTF fonts for avatar generation
2018-02-20 08:21:04 +01:00
Nextcloud bot 16a4e7192c [tx-robot] updated from transifex 2018-02-20 01:12:21 +00:00
Roeland Jago Douma a4159378be Avatar generation use ttf (for ancient compatibility)
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-02-19 22:12:56 +01:00
Roeland Jago Douma 535816a6d4 Add TTF of OpenSand-{Ligh,Semibold}
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-02-19 22:12:51 +01:00
Nextcloud bot b5029f8975 [tx-robot] updated from transifex 2018-02-19 01:12:17 +00:00
Nextcloud bot 3d06d946b0 [tx-robot] updated from transifex 2018-02-18 01:12:28 +00:00
Morris Jobke 577a3cf145 Merge pull request #8407 from nextcloud/stable13-8376-devgals
[stable13] Fix edit tag textbox size
2018-02-17 15:38:34 +01:00
Aastha Gupta 09dbcd9647 Fix edit tag textbox size
Fixes #7586

Signed-off-by: Aastha Gupta <aastha.gupta4104@gmail.com>
2018-02-17 15:56:59 +05:30
Nextcloud bot b631cc1286 [tx-robot] updated from transifex 2018-02-17 01:12:30 +00:00
Morris Jobke 964b511b39 Merge pull request #8395 from nextcloud/stable13-8382-make-acceptance-tests-for-comments-more-consistent-with-the-others
[stable13] Make acceptance tests for comments more consistent with the others
2018-02-16 14:33:49 +01:00
Daniel Calviño Sánchez 5fd7de5275 Take into account the comment message when looking for it
Instead of checking that the list contains one comment it is now checked
that a comment with certain message is visible. This makes the step (and
the locator) more reusable in future tests and also simplifies the code.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-02-16 12:24:35 +01:00
Daniel Calviño Sánchez d9e66b2114 Adjust timeouts in the step to create a new comment
Depending on the previous steps the new comment field may be already
shown or not when the step to create a new comment is executed.
Therefore, the timeout was increased from 2 to the "standard" 10 seconds
used in other tests.

If the new comment field was found there is no need to use a timeout
when looking for the new comment button; it is either there or not, it
will not appear after some time.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-02-16 12:24:35 +01:00
Daniel Calviño Sánchez f6737e43e9 Move locators above step definitions
The locators are moved above the step definitions for consistency with
other context files; besides that I made some minor adjustments for
consistency too in the locator descriptions and identation, and moved
the locators for ".newCommentRow" descendants together.

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-02-16 12:24:35 +01:00
Daniel Calviño Sánchez 38a03f3193 Add acceptance tests for comments to Drone
Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-02-16 12:24:34 +01:00
Nextcloud bot de9865b9d9 [tx-robot] updated from transifex 2018-02-16 01:12:34 +00:00
Nextcloud bot ef367f8bfe [tx-robot] updated from transifex 2018-02-14 21:37:55 +00:00
Nextcloud bot adb9ad29fa [tx-robot] updated from transifex 2018-02-14 01:12:17 +00:00
Nextcloud bot 7d1c9eef8d [tx-robot] updated from transifex 2018-02-13 10:48:56 +00:00
Roeland Jago Douma 57e3900095 Merge pull request #8261 from nextcloud/s3-folder-delete-13
[13] Fix deleting folders when using s3 external storage
2018-02-13 07:45:02 +01:00
Nextcloud bot 2e271313c9 [tx-robot] updated from transifex 2018-02-12 21:34:01 +00:00
Robin Appelman 2a6f8e65c2 fix invalidating folder cache for s3
Signed-off-by: Robin Appelman <robin@icewind.nl>
2018-02-12 20:23:10 +01:00
Robin Appelman 3257bf2424 adjust s3 bulk delete to new sdk syntax
Signed-off-by: Robin Appelman <robin@icewind.nl>
2018-02-12 20:23:10 +01:00
Morris Jobke 4c21fc802f Merge pull request #8309 from nextcloud/8308_13
[stable13] Show open graph preview in WhatsApp
2018-02-12 14:24:17 +01:00
Roeland Jago Douma ad7c31914f Show open graph preview in WhatsApp
Whatsapp is picky about the size of the open graph images.
So we do some special handling.

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-02-12 11:12:27 +01:00
John Molakvoæ e47e1f6bdd Merge pull request #8287 from nextcloud/stable13-8165
[13] Remove jquery ui background image
2018-02-10 00:05:01 +01:00
John Molakvoæ 3f91eaedfc Merge pull request #8286 from nextcloud/stable13-8155
[13] Fix styling issues of guest pages #8155
2018-02-10 00:04:40 +01:00
Julius Härtl f248c7a583 Remove jquery ui background image
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-02-09 17:47:19 +01:00
Julius Härtl ef571d69f3 Add space on guest pages with custom logo
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-02-09 17:46:48 +01:00
Julius Härtl 1b3e3dfada Load guest css on any guest and error page
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-02-09 17:46:48 +01:00
Julius Härtl e3fb91756a Make sure theming logo css only applies when a logo is set
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-02-09 17:46:47 +01:00
Nextcloud bot 9c9c438c8b [tx-robot] updated from transifex 2018-02-09 15:29:20 +00:00
Morris Jobke 832c0c480b Merge pull request #8271 from nextcloud/13-8270
[stable13] Update CRL to revoke files_rightclick
2018-02-09 09:57:36 +01:00
Morris Jobke 9586dc6c92 Merge pull request #8145 from nextcloud/13-unperl-l10n
[stable13] Remove old perl script to update l10n files
2018-02-09 09:56:26 +01:00
Morris Jobke 9bc0de9ab6 Update CRL to revoke files_rightclick
See https://github.com/nextcloud/app-certificate-requests/pull/134

Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-02-09 09:44:55 +01:00
Nextcloud bot 2845166e2a [tx-robot] updated from transifex 2018-02-09 01:11:05 +00:00
Roeland Jago Douma 71cadf465b Merge pull request #8264 from nextcloud/fix_dev_man_link_13
[stable13] Link to NC13 dev manual
2018-02-08 20:05:35 +01:00
Morris Jobke 95ac2e31ae Remove old perl script to update l10n files
Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-02-08 18:22:04 +01:00
Roeland Jago Douma a6bb42d3e8 [stable13] Link to NC13 dev manual
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-02-08 15:13:51 +01:00
Morris Jobke 197c97e242 Merge pull request #8102 from nextcloud/s3-uploader-13
[13] Use S3Client::upload instead of splitting single/multipart upload ourselves
2018-02-08 14:31:23 +01:00
Morris Jobke e2cb6a3b3c Merge pull request #8183 from robert-scheck/pki-validation-stable13
[stable13] Handle SSL certificate verifications for others than Let's Encrypt
2018-02-08 11:02:33 +01:00
Joas Schilling 78e3b6400a Merge pull request #8253 from nextcloud/13-8252
[stable13] Remove invalid link to documentation
2018-02-08 10:20:39 +01:00
Roeland Jago Douma 55d5868da5 Update tests
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-02-08 10:16:38 +01:00
Roeland Jago Douma f1cd334281 Don't perform CSRF check on OCS routes with Bearer auth
Fixes #5694

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-02-08 10:16:38 +01:00
Roeland Jago Douma 202dd62951 Merge pull request #8250 from nextcloud/8233_13
[stable13] actually return stream from swift
2018-02-08 09:07:33 +01:00
Morris Jobke 7701c7fab6 Remove invalid link to documentation
Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-02-08 08:46:36 +01:00
Robin Appelman 6296c498b2 actually return stream from swift
Signed-off-by: Robin Appelman <robin@icewind.nl>
2018-02-08 08:10:08 +01:00
Nextcloud bot 5e3cb24efa [tx-robot] updated from transifex 2018-02-08 01:10:40 +00:00
Joas Schilling 36eb93deac Merge pull request #8228 from nextcloud/dav-dir-exception-previous-13
[13] keep previous exception when transforming to dav exception
2018-02-07 17:05:27 +01:00
Robin Appelman 38cb28db1f keep previous exception when transforming to dav exception
Signed-off-by: Robin Appelman <robin@icewind.nl>
2018-02-07 14:44:11 +01:00
Nextcloud bot f8740a1f0c [tx-robot] updated from transifex 2018-02-07 11:32:08 +00:00
Roeland Jago Douma 7486d021b1 Merge pull request #8197 from nextcloud/stable13-8144
[stable13] Repair step to clear frontend related caches
2018-02-07 09:02:37 +01:00
Nextcloud bot 1ec43c8265 [tx-robot] updated from transifex 2018-02-07 01:10:36 +00:00
Morris Jobke b16824db31 Merge pull request #8195 from nextcloud/13-8172
[stable13] Use a phan version instead of master
2018-02-06 16:41:58 +01:00
Roeland Jago Douma b55b1b5854 Merge pull request #8045 from nextcloud/8002_13
[stable13] Dont polute the log on DAV emaillogin
2018-02-06 15:34:28 +01:00
Roeland Jago Douma c1423eec24 Use a phan version instead of master
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-02-06 14:20:30 +01:00
Roeland Jago Douma b837d3f332 Fix tests
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-02-06 12:32:51 +01:00
Julius Härtl 69b22c2d61 Move depsCache clearing to SCSSCacher/JSCombiner
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-02-06 12:32:50 +01:00
Julius Härtl bf24b4db24 Add tests and class mapping
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-02-06 12:32:50 +01:00
Julius Härtl 31313178a5 Add repair step to clear frontend related caches
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-02-06 12:32:48 +01:00
Morris Jobke b2068704e7 Merge pull request #8156 from nextcloud/stable13-8078
[Stable13] Scss hardening
2018-02-06 12:17:45 +01:00
Morris Jobke 0fc97b2104 Merge pull request #8177 from nextcloud/8160_13
[stable13] Do not try to get the jailed path if we can't find the id
2018-02-06 11:18:46 +01:00
Nextcloud bot 9da8032b39 [tx-robot] updated from transifex 2018-02-06 01:10:34 +00:00
Morris Jobke 3b4285e13f Merge pull request #8187 from nextcloud/13-final
Final 13.0.0
2018-02-06 01:24:06 +01:00
Morris Jobke bc171d46e6 Final 13.0.0
Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-02-05 18:20:47 +01:00
Robert Scheck de07c82a4d Handle SSL certificate verifications for others than Let's Encrypt
Do no longer (wrongly) rewrite URLs like

  * http://example.net/.well-known/pki-validation/file.txt (Comodo)
  * http://example.net/.well-known/pki-validation/fileauth.txt (DigiCert, Thawte, GeoTrust)
  * http://example.net/.well-known/pki-validation/gsdv.txt (GlobalSign)
  * http://example.net/.well-known/pki-validation/starfield.htm (Starfield, GoDaddy)
  * http://example.net/.well-known/pki-validation/swisssign-check.txt (SwissSign)

for automated SSL certificate verifications. All (common commercial)
certificate authorities (CA) except Let's Encrypt (via ACME) seem to
use "pki-validation" rather "acme-challenge" for their domain control
validation (DCV).

Signed-off-by: Robert Scheck <robert@fedoraproject.org>
2018-02-05 15:37:23 +01:00
Roeland Jago Douma b88aeb2166 Do not try to get the jailed path if we can't find the id
Fixes #8047

If we can't find the file by id there we should just return null instead
of trying to get the jailed path of null.

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-02-05 12:42:47 +01:00
Nextcloud bot 976e5e35f7 [tx-robot] updated from transifex 2018-02-05 01:10:30 +00:00
Nextcloud bot e268181b84 [tx-robot] updated from transifex 2018-02-04 01:10:40 +00:00
Nextcloud bot 064ff027fd [tx-robot] updated from transifex 2018-02-03 01:10:43 +00:00
Morris Jobke 9e907901a0 Merge pull request #8151 from nextcloud/13-8150
[stable13] Update CRL because user_sql cert was lost
2018-02-02 13:34:28 +01:00
Julius Härtl 7870cc2b67 Fix theming tests
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-02-02 13:06:50 +01:00
Julius Härtl 9915ebb75f Add tests for URL rewriting
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-02-02 13:06:04 +01:00
Julius Härtl 106af04355 Do not rewrite absolute URLs
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-02-02 13:05:58 +01:00
Julius Härtl cee941a6a3 Clear injectect variables when resetting the cache
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-02-02 13:05:52 +01:00
Julius Härtl 76c79ff18f Only override image styles if the theming values are set
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-02-02 13:05:41 +01:00
Julius Härtl 73ae7b0c5f Make sure that injected variables do not break the CSS generation
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-02-02 13:05:25 +01:00
Julius Härtl d8e0a6ee32 SCSS files are only cached if their size is > 0
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-02-02 13:05:03 +01:00
Morris Jobke b2e3e29266 Merge pull request #8142 from nextcloud/13-update-server
[stable13] Use correct update server
2018-02-02 12:18:29 +01:00
Morris Jobke 254be1dacd Update CRL because user_sql cert was lost
* see https://github.com/nextcloud/app-certificate-requests/pull/129

Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-02-02 11:59:24 +01:00
Nextcloud bot 6989c65acf [tx-robot] updated from transifex 2018-02-02 01:10:28 +00:00
Nextcloud bot 501685288b [tx-robot] updated from transifex 2018-02-01 18:28:19 +00:00
Nextcloud bot d5e56b34c4 [tx-robot] updated from transifex 2018-02-01 17:20:02 +00:00
Christoph Wurst 62f4454d99 Merge pull request #8138 from nextcloud/13-update-doc-version
Update doc link version to 13
2018-02-01 14:45:45 +01:00
Morris Jobke d9e229ab70 Use correct update server
Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-02-01 14:43:53 +01:00
Morris Jobke f46573d836 Update doc link version to 13
Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-02-01 13:53:24 +01:00
Nextcloud bot 2e6e969fbc [tx-robot] updated from transifex 2018-02-01 01:11:06 +00:00
Morris Jobke 88d5f6ec63 Merge pull request #8127 from nextcloud/13-final-rc
13.0.0 RC 4
2018-01-31 20:31:17 +01:00
Morris Jobke 2cc1cdba6f 13.0.0 RC 4
Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-01-31 17:31:18 +01:00
Morris Jobke c39a40f15f Merge pull request #8126 from nextcloud/13-8121
[stable13] Create the migrations table also with the UTF8mb4 collation
2018-01-31 17:29:00 +01:00
Roeland Jago Douma dabce9685b Merge pull request #8124 from nextcloud/app-nav-flex-margins-fix
[stable13] Fixed app navigation flex margins
2018-01-31 15:56:18 +01:00
Joas Schilling 119de6467f Create the migrations table also with the UTF8mb4 collation
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-01-31 15:54:28 +01:00
John Molakvoæ (skjnldsv) 22c083b58a Fixed app navigation flex margins
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
2018-01-31 14:51:27 +01:00
Morris Jobke bb7a2b2329 Merge pull request #8073 from nextcloud/stable13-8069
[stable13] do not catch and ignore ServerNotAvailable in the wrong spot
2018-01-31 14:46:55 +01:00
Morris Jobke 10110e85eb Merge pull request #8116 from nextcloud/8111_13
[stable13] Only handle encrypted property on folders
2018-01-31 14:46:18 +01:00
Nextcloud bot fb11969916 [tx-robot] updated from transifex 2018-01-31 01:11:04 +00:00
Roeland Jago Douma f924a6d7d9 Only handle encrypted property on folders
Exposing the encrypted property is required for E2E. However, there is
no need to expose this on files as then it is server side encryption
(which the clients don't care about).

Better to not confuse the output.

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-01-30 21:56:32 +01:00
Nextcloud bot c30e958dac [tx-robot] updated from transifex 2018-01-30 01:11:20 +00:00
Robin Appelman 7ab3a7e2c3 Use S3Client::upload instead of splitting single/multipart upload ourselves
Signed-off-by: Robin Appelman <robin@icewind.nl>
2018-01-29 16:11:05 +01:00
Nextcloud bot 7b227d8712 [tx-robot] updated from transifex 2018-01-29 01:11:05 +00:00
Nextcloud bot 5700467c29 [tx-robot] updated from transifex 2018-01-27 01:11:03 +00:00
Arthur Schiwon d61dd36fdd do not catch ServerNotAvailable
might cause the user to be unavailable (race condition).

Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
2018-01-26 15:35:26 +01:00
Morris Jobke d82d1a8a81 Merge pull request #8027 from nextcloud/13.0.0-last-rc
13.0.0 RC3
2018-01-26 15:27:57 +01:00
Morris Jobke fabf75a7d3 13.0.0 RC3
Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-01-26 14:43:20 +01:00
Nextcloud bot 0aca61d73e [tx-robot] updated from transifex 2018-01-26 01:11:04 +00:00
Roeland Jago Douma 2bed7a7f95 Fix tests
Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-01-25 12:23:56 +01:00
Roeland Jago Douma 9dfd3544c2 Don't polute log when loggin into dav with email
* We first try the email as username but this fails
* Then we get the uid from the email and try again

We should not log the first attempt since it polutes the log with failed
login attempts while the login actually is valid.

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-01-25 12:23:50 +01:00
Nextcloud bot e79a755d08 [tx-robot] updated from transifex 2018-01-25 01:11:19 +00:00
Roeland Jago Douma d76f08dfbd Merge pull request #8034 from nextcloud/13-8032
[stable13] Fix missing clipboard icon in shared links
2018-01-24 19:19:46 +01:00
Daniel Calviño Sánchez 326af0c9c3 Fix missing clipboard icon in shared links
The clipboard icon in shared links appears either directly on the link
input field or, if any social sharing app is enabled, in a menu. The
clipboard icon uses the same CSS rules as other icons (like the
information icon) to be posioned on the end of the input field, and
those rules have to be "cancelled" when the icon is shown in the menu.

Fixes #7990

Signed-off-by: Daniel Calviño Sánchez <danxuliu@gmail.com>
2018-01-24 17:25:50 +01:00
Morris Jobke 52149d2c54 Merge pull request #8031 from nextcloud/7921_12
[stable13] Removed additional and uneccessary request on password reset, to fix redirection afterwards.
2018-01-24 17:24:51 +01:00
Morris Jobke a0f62b71c8 Merge pull request #8030 from nextcloud/7986_12
[stable13] If the preview is size 0 it is invalid
2018-01-24 16:40:44 +01:00
Roeland Jago Douma 1a21524f6f Merge pull request #8025 from nextcloud/13-8020
[stable13] Make sure we always know for sure if an avatar is generated or not
2018-01-24 16:28:55 +01:00
Morris Jobke 76636dea9c Merge pull request #8029 from nextcloud/13-7991
[stable13] Send a proper response for status.php on trusted domain error
2018-01-24 16:22:06 +01:00
Luca Adrian Lindhorst 6b954e6cd6 Removed additional and uneccessary request on password reset, to fix redirection afterwards.
Signed-off-by: Luca Adrian Lindhorst <info@lucalindhorst.de>
2018-01-24 16:14:37 +01:00
Roeland Jago Douma f259e1cb8c If the preview is size 0 it is invalid
* delete it
* throw a NotFound Exception
  - This should a proper 404 to the user
  - Next time it is then regenerated

Signed-off-by: Roeland Jago Douma <roeland@famdouma.nl>
2018-01-24 16:11:36 +01:00
Morris Jobke 986623e2ac Send a proper response for status.php on trusted domain error
* fixes #7732

Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-01-24 15:42:25 +01:00
Julius Härtl 0209690d55 Make sure we always know for sure if an avatar is generated or not
Signed-off-by: Julius Härtl <jus@bitgrid.net>
2018-01-24 15:05:38 +01:00
Nextcloud bot 3b35c226ce [tx-robot] updated from transifex 2018-01-24 01:11:02 +00:00
Robin Appelman 3d10c3ace5 increase the time we wait for smb notifications in the test
Signed-off-by: Robin Appelman <robin@icewind.nl>
2018-01-23 09:54:34 +01:00
Nextcloud bot 924298f740 [tx-robot] updated from transifex 2018-01-23 01:11:03 +00:00
Nextcloud bot 823a14fae6 [tx-robot] updated from transifex 2018-01-22 01:10:53 +00:00
Nextcloud bot 883817e62a [tx-robot] updated from transifex 2018-01-21 01:11:04 +00:00
Nextcloud bot 4c431d39eb [tx-robot] updated from transifex 2018-01-20 01:11:10 +00:00
Roeland Jago Douma 1ecf10e26d Merge pull request #7963 from nextcloud/smb-2.0.4-13
[13] update icewind/smb to 2.0.4
2018-01-19 20:24:21 +01:00
Robin Appelman 31b922d2f5 update icewind/smb to 2.0.4
Signed-off-by: Robin Appelman <robin@icewind.nl>
2018-01-19 16:23:22 +01:00
Nextcloud bot bec72bf9ff [tx-robot] updated from transifex 2018-01-19 01:11:08 +00:00
Morris Jobke 6719c7723a Merge pull request #7940 from nextcloud/13.0.0-rc2-prep
13.0.0 RC2
2018-01-18 17:41:43 +01:00
Morris Jobke 0b3623a71d 13.0.0 RC2
Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-01-18 17:05:46 +01:00
Morris Jobke eb03435377 Merge pull request #7944 from nextcloud/backport/7912/correctly-drop-owncloud-migrations-table
[stable13] Correctly drop the ownCloud migrations table
2018-01-18 17:03:15 +01:00
Morris Jobke b7da6f13ff Merge pull request #7942 from nextcloud/7941-stable13
[stable13] remove hardcoded sharepoint icon path
2018-01-18 16:47:55 +01:00
Morris Jobke 0a76d72a1d Merge pull request #7943 from nextcloud/backport/7812/make-sure-the-arrays-are-arrays
[stable13] Make sure the arrays are arrays
2018-01-18 16:47:16 +01:00
Morris Jobke 9cda3206ff Properly catch InvalidTokenException for better error response
Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-01-18 16:11:21 +01:00
Joas Schilling 809928c176 Correctly drop the ownCloud migrations table
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-01-18 15:59:05 +01:00
Joas Schilling 73a6717016 Make sure the arrays are arrays
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-01-18 15:56:24 +01:00
Arthur Schiwon 1703c25b26 remove hardcoded sharepoint icon path
it does not exist and if it would, it was not themable

Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
2018-01-18 15:47:25 +01:00
Daniel Calviño Sánchez a0499e0258 Merge pull request #7932 from nextcloud/7914-stable13
[stable13] format self-mentions, but don't offer them
2018-01-18 14:20:26 +01:00
Arthur Schiwon 92bc33dd1e Backport of format self-mentions, but don't offer them #7914
comments should compile mentions also if done by author

it is used by clients for formatting reasons, there is no reason not format
the author if her handle is included in the comment body.
It is unrelated to sending out notifications.

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

do not offer the handle of the current user for auto completion

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

add types to php doc

Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
2018-01-18 12:08:08 +01:00
Nextcloud bot 266c64069f [tx-robot] updated from transifex 2018-01-18 01:10:52 +00:00
Roeland Jago Douma 414d6e2184 Merge pull request #7915 from nextcloud/backport/7909/fix-migration-type-hints
Fix the type hints of migrations and correctly inject the wrapped sch…
2018-01-17 14:55:18 +01:00
Joas Schilling ed999066e5 Fix the type hints of migrations and correctly inject the wrapped schema into migrations
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-01-17 13:53:09 +01:00
Morris Jobke 9efdd684c4 Merge pull request #7903 from nextcloud/13-7891
[stable13] Fix systemtags/list to be compliant
2018-01-17 11:40:56 +01:00
Nextcloud bot c042ae8d61 [tx-robot] updated from transifex 2018-01-17 01:11:11 +00:00
Morris Jobke 7ea3623cd9 Merge pull request #7887 from nextcloud/backport/7879/dont-disable-shipped-apps-on-errors
[stable13] Keep all shipped apps enabled because they should be okay
2018-01-16 21:52:36 +01:00
Morris Jobke e643af16d3 Fix systemtags/list to be compliant
Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-01-16 21:48:32 +01:00
Roeland Jago Douma 4b2e98953b Merge pull request #7883 from nextcloud/search-and-13
[13] Support arbitrary number of arguments for d:or and d:and in search queries
2018-01-16 20:21:08 +01:00
Joas Schilling c32a13fb5b Merge pull request #7886 from nextcloud/13-7885
[stable13] Add OCP\User deprecations to app code checker
2018-01-16 14:17:36 +01:00
Joas Schilling d639dfacb7 Keep all shipped apps enabled because they should be okay
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-01-16 13:41:09 +01:00
Morris Jobke 0fafa794da Add OCP\User deprecations to app code checker
Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-01-16 13:33:58 +01:00
Robin Appelman 3a1390fdb7 Support arbitrary number of arguments for d:or and d:and in search queries
Signed-off-by: Robin Appelman <robin@icewind.nl>
2018-01-16 13:27:52 +01:00
Christoph Wurst c25da25180 Merge pull request #7878 from nextcloud/13-7877
[stable13] Deprecated checkLoggedIn and other old ways to access control
2018-01-16 12:23:39 +01:00
Morris Jobke 09908a737f Deprecated checkLoggedIn and other old ways to access control
Signed-off-by: Morris Jobke <hey@morrisjobke.de>
2018-01-16 10:43:03 +01:00
Nextcloud bot 43a53c0c8e [tx-robot] updated from transifex 2018-01-16 01:11:05 +00:00
Morris Jobke 3baa5fada8 Merge pull request #7806 from nextcloud/fix-7805
Fix bug with proxies
2018-01-15 00:50:25 +01:00
Joas Schilling f2706cb572 Add unit test
Signed-off-by: Joas Schilling <coding@schilljs.com>
2018-01-15 00:49:28 +01:00
Mario Danic c7eaa26f73 Fix bug with proxies
Signed-off-by: Mario Danic <mario@lovelyhq.com>
2018-01-15 00:49:22 +01:00
4504 changed files with 115107 additions and 224438 deletions
+3 -7
View File
@@ -1,15 +1,11 @@
codecov:
branch: master
ci:
- drone.nextcloud.com
- !scrutinizer-ci.com
coverage:
precision: 2
round: down
range: "70...100"
status:
project: off
patch: off
comment: off
comment:
layout: "header, diff, changes, uncovered, tree"
behavior: default
+932 -2300
View File
File diff suppressed because it is too large Load Diff
+1 -8
View File
@@ -1,5 +1,6 @@
# the default generated dir + db file
/data
/owncloud
/config/config.php
/config/*.config.php
/config/mimetype*.json
@@ -12,7 +13,6 @@
# ignore all apps except core ones
/apps*/*
!/apps/accessibility
!/apps/comments
!/apps/dav
!/apps/files
@@ -42,9 +42,6 @@
/apps/files_external/3rdparty/irodsphp/prods/test*
/apps/files_external/tests/config.*.php
# apps modules
/apps/*/node_modules
# ignore themes except the example and the README
/themes/*
@@ -121,7 +118,6 @@ nbproject
/build/jsdocs/
/npm-debug.log
/PhantomJS_*
/build/package-lock.json
# puphpet
puphpet
@@ -139,9 +135,6 @@ Vagrantfile
/tests/autotest*
/tests/data/lorem-copy.txt
/tests/data/testimage-copy.png
/tests/ui-regression/out/
/tests/ui-regression/node_modules/
/tests/ui-regression/package-lock.json
/config/config-autotest-backup.php
/config/autoconfig.php
clover.xml
+2 -3
View File
@@ -16,7 +16,6 @@
Header set X-Robots-Tag "none"
Header set X-Download-Options "noopen"
Header set X-Permitted-Cross-Domain-Policies "none"
Header set Referrer-Policy "no-referrer"
SetEnv modHeadersAvailable true
</IfModule>
@@ -24,7 +23,7 @@
<FilesMatch "\.(css|js|svg|gif)$">
Header set Cache-Control "max-age=15778463"
</FilesMatch>
# Let browsers cache WOFF files for a week
<FilesMatch "\.woff$">
Header set Cache-Control "max-age=604800"
@@ -64,7 +63,7 @@
RewriteRule ^\.well-known/caldav /remote.php/dav/ [R=301,L]
RewriteRule ^remote/(.*) remote.php [QSA,L]
RewriteRule ^(?:build|tests|config|lib|3rdparty|templates)/.* - [R=404,L]
RewriteCond %{REQUEST_URI} !^/\.well-known/(acme-challenge|pki-validation)/.*
RewriteCond %{REQUEST_URI} !^/.well-known/(acme-challenge|pki-validation)/.*
RewriteRule ^(?:\.|autotest|occ|issue|indie|db_|console).* - [R=404,L]
</IfModule>
<IfModule mod_mime.c>
+2
View File
@@ -0,0 +1,2 @@
pattern = "(?i):shipit:|:\\+1:|LGTM|👍"
self_approval_off = true
-6
View File
@@ -127,9 +127,3 @@ file_filter = translationfiles/<lang>/workflowengine.po
source_file = translationfiles/templates/workflowengine.pot
source_lang = en
type = PO
[nextcloud.accessibility]
file_filter = translationfiles/<lang>/accessibility.po
source_file = translationfiles/templates/accessibility.pot
source_lang = en
type = PO
+1 -1
View File
@@ -58,7 +58,7 @@ like `git config --global alias.ci 'commit -s'`. Now you can commit with
In case you are not sure how to add or update the license header correctly please have a look at [contribute/HowToApplyALicense.md][applyalicense]
[devmanual]: https://docs.nextcloud.org/server/13/developer_manual/
[devmanual]: https://docs.nextcloud.org/server/12/developer_manual/
[dcofile]: https://github.com/nextcloud/server/blob/master/contribute/developer-certificate-of-origin
[applyalicense]: https://github.com/nextcloud/server/blob/master/contribute/HowToApplyALicense.md
+2 -15
View File
@@ -36,16 +36,7 @@
[…learn more about how to get support for Nextcloud here!](https://nextcloud.com/support)
## Join the team :family:
### How to contribute
1. [Set up your local development environment](https://docs.nextcloud.com/server/14/developer_manual/general/devenv.html) :rocket:
2. [Pick a good first issue](https://github.com/nextcloud/server/labels/good%20first%20issue) :notebook:
3. Create a branch, a [Pull Request](https://opensource.guide/how-to-contribute/#opening-a-pull-request) and `@mention` the people from the issue :computer:
4. Wait for it to get merged and :tada:
### Contribution Guidelines
## Contribution Guidelines
All contributions to this repository from June, 16 2016 on are considered to be
licensed under the AGPLv3 or any later version.
@@ -65,7 +56,7 @@ Please review the [guidelines for contributing](https://github.com/nextcloud/ser
More information how to contribute: [https://nextcloud.com/contribute/](https://nextcloud.com/contribute/)
### Running master checkouts
## Running master checkouts
Third-party components are handled as git submodules which have to be initialized first. So aside from the regular git checkout invoking `git submodule update --init` or a similar command is needed, for details see Git documentation.
@@ -74,7 +65,3 @@ Several apps that are included by default in regular releases such as [firstrunw
That aside Git checkouts can be handled the same as release archives.
Note they should never be used on production systems.
## Tools we use
[![BrowserStack](https://user-images.githubusercontent.com/45821/41675934-61fa3442-74c4-11e8-8c8e-90768c56ba08.png)](https://www.browserstack.com/)
-12
View File
@@ -1,12 +0,0 @@
{
"presets": [
[
"env",
{
"targets": {
"browsers": ["last 2 versions", "not ie <= 11"]
}
}
]
]
}
-9
View File
@@ -1,9 +0,0 @@
root = true
[*]
charset = utf-8
indent_style = tab
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
-16
View File
@@ -1,16 +0,0 @@
module.exports = {
env: {
browser: true,
es6: true
},
extends: 'eslint:recommended',
parserOptions: {
sourceType: 'module'
},
rules: {
indent: ['error', 'tab'],
'linebreak-style': ['error', 'unix'],
quotes: ['error', 'single'],
semi: ['error', 'always']
}
};
-12
View File
@@ -1,12 +0,0 @@
.DS_Store
node_modules/
dist/
npm-debug.log
yarn-error.log
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
-3
View File
@@ -1,3 +0,0 @@
{
"esversion": 6
}
-26
View File
@@ -1,26 +0,0 @@
all: dev-setup build-js-production
dev-setup: clean clean-dev npm-init
npm-init:
npm install
npm-update:
npm update
build-js:
npm run dev
build-js-production:
npm run build
watch-js:
npm run watch
clean:
rm -f js/accessibility.js
rm -f js/accessibility.js.map
clean-dev:
rm -rf node_modules
-22
View File
@@ -1,22 +0,0 @@
# Accessibility ♿
> This app provide multiple features to ease the use of nextcloud.
## Build Setup
``` bash
# install dependencies
make dev-setup
# build for development
make build-js
# build for development and watch edits
make watch-js
# build for production with minification
make build-js-production
# clean output files
make clean
```
-30
View File
@@ -1,30 +0,0 @@
<?php
declare (strict_types = 1);
/**
* @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
$app = new \OCA\Accessibility\AppInfo\Application();
// Separate from the constructor since the route are not initialized before that
// 1. create the app
// 2. generate css route and inject
$app->injectCss();
-23
View File
@@ -1,23 +0,0 @@
<?xml version="1.0"?>
<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
<id>accessibility</id>
<name>Accessibility</name>
<summary>Accessibility options for nextcloud</summary>
<description><![CDATA[Provides multiple accessibilities options to ease your use of nextcloud]]></description>
<version>1.0.1</version>
<licence>agpl</licence>
<author>John Molakvoæ</author>
<namespace>Accessibility</namespace>
<category>accessibility</category>
<default_enable/>
<dependencies>
<nextcloud min-version="14" max-version="14"/>
</dependencies>
<default_enable/>
<bugs>https://github.com/nextcloud/server/issues</bugs>
<settings>
<personal>OCA\Accessibility\Settings\Personal</personal>
<personal-section>OCA\Accessibility\Settings\PersonalSection</personal-section>
</settings>
</info>
-40
View File
@@ -1,40 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
return [
'routes' => [
['name' => 'accessibility#getCss', 'url' => '/css/user-{md5}', 'verb' => 'GET'],
],
'ocs' => [
[
'name' => 'Config#getConfig',
'url' => '/api/v1/config',
'verb' => 'GET',
],
[
'name' => 'Config#setConfig',
'url' => '/api/v1/config/{key}',
'verb' => 'POST',
],
]
];
-22
View File
@@ -1,22 +0,0 @@
@font-face {
font-family: 'OpenDyslexic';
font-style: normal;
font-weight: 300;
src: url('../fonts/OpenDyslexic-Regular.woff') format('woff');
}
@font-face {
font-family: 'OpenDyslexic';
font-style: normal;
font-weight: normal;
src: url('../fonts/OpenDyslexic-Regular.woff') format('woff');
}
@font-face {
font-family: 'OpenDyslexic';
font-style: normal;
font-weight: 600;
src: url('../fonts/OpenDyslexic-Bold.woff') format('woff');
}
$font-face: OpenDyslexic, 'Open Sans', Frutiger, Calibri, 'Myriad Pro', Myriad, sans-serif;
-59
View File
@@ -1,59 +0,0 @@
.preview-list {
display: flex;
flex-wrap: wrap;
}
.preview {
display: flex;
flex-direction: column;
min-width: 250px;
max-width: 400px;
flex: 1 1 300px;
border: 1px solid var(--color-border);
padding: 10px;
border-radius: var(--border-radius);
transition: all 200ms ease-in-out;
filter: drop-shadow(0 1px 2px var(--color-box-shadow));
background-color: var(--color-main-background);
opacity: 0.9;
margin: 10px;
position: relative;
&,
* {
cursor: pointer;
user-select: none;
}
&:hover,
&:focus,
&.selected {
filter: drop-shadow(0 1px 4px var(--color-box-shadow));
opacity: 1;
}
.preview-image {
height: 200px;
background-position: top left;
background-size: cover;
background-repeat: no-repeat;
}
h3 {
display: flex;
justify-content: space-between;
line-height: 1em;
align-items: center;
}
p {
text-align: justify;
}
.icon-checkmark-color {
transition: all 100ms ease-in-out;
border-radius: 1em;
padding: 4px 5px 4px 20px;
background-position: 4px center;
opacity: 0;
visibility: hidden;
}
&.selected .icon-checkmark-color {
opacity: 1;
visibility: visible;
box-shadow: 0 0 0 1px var(--color-success);
}
}
-52
View File
@@ -1,52 +0,0 @@
// SCSS variables
$color-main-text: #d8d8d8;
$color-main-background: #181818;
$color-background-dark: lighten($color-main-background, 4%);
$color-background-darker: lighten($color-main-background, 8%);
$color-text-maxcontrast: darken($color-main-text, 30%);
$color-text-light: darken($color-main-text, 10%);
$color-text-lighter: darken($color-main-text, 20%);
$color-loading-light: #777;
$color-loading-dark: #ccc;
$color-box-shadow: rgba(darken($color-main-background, 70%), 0.5);
$color-border: lighten($color-main-background, 7%);
$color-border-dark: lighten($color-main-background, 14%);
#app-navigation > ul > li > a:first-child,
#app-navigation > ul > li > ul > li > a:first-child,
#expanddiv a {
img {
filter: invert(100%);
}
}
.bubble,
.app-navigation-entry-menu,
.popovermenu {
li {
> button,
> a,
> .menuitem {
> img {
filter: invert(100%);
}
}
}
}
.bubble,
.app-navigation-entry-menu,
.popovermenu,
#header .menu {
border: 1px solid var(--color-border);
}
// since svg icons are inverted, revert to white for the header
.header-right > * {
[class^='icon-'], [class*=' icon-'] {
filter: invert(100%);
}
}
@@ -1,57 +0,0 @@
// Fonts
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: normal;
src: local('Open Sans'), local('OpenSans'),
url('../../../core/fonts/OpenSans-Regular.woff') format('woff');
}
/* overriding default light */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 300;
src: local('Open Sans'), local('OpenSans'),
url('../../../core/fonts/OpenSans-Regular.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 500 700;
src: local('Open Sans Bold'), local('OpenSans-Bold'),
url('../../../core/fonts/OpenSans-Bold.woff') format('woff');
}
// SCSS variables
$color-main-text: #000;
$color-main-background: #fff;
$color-background-dark: darken($color-main-background, 30%);
$color-background-darker: darken($color-main-background, 30%);
$color-text-maxcontrast: $color-main-text;
$color-text-light: $color-main-text;
$color-text-lighter: $color-main-text;
$color-loading-light: #ddd;
$color-loading-dark: #000;
$color-box-shadow: $color-main-text;
$color-border: darken($color-main-background, 50%);
$color-border-dark: darken($color-main-background, 50%);
$font-face: 'Open Sans', Frutiger, Calibri, 'Myriad Pro', Myriad, sans-serif;
// Font weight reset
body {
font-weight: 400;
}
[class^='icon-'], [class*=' icon-'],
.action {
opacity: 1 !important;
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-76
View File
@@ -1,76 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
width="16"
height="16"
viewBox="0 0 16 16"
sodipodi:docname="app-dark.svg"
inkscape:version="0.92.2 5c3e80d, 2017-08-06">
<metadata
id="metadata8">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1880"
inkscape:window-height="993"
id="namedview4"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
inkscape:zoom="36.460193"
inkscape:cx="8.4752826"
inkscape:cy="18.273624"
inkscape:window-x="20"
inkscape:window-y="67"
inkscape:window-maximized="0"
inkscape:current-layer="g848"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<g
id="g848"
transform="matrix(1.1307959,0,0,1.0801738,-1.0463882,-0.84269722)"
style="stroke-width:0.90481776;fill:#000000">
<circle
r="1.9587879"
cy="2.8315151"
cx="7.990303"
id="path844"
style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.90481776;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke markers fill" />
<path
sodipodi:nodetypes="scsssscsccccczzcccccssssccsscs"
inkscape:connector-curvature="0"
id="path843"
d="m 2.3519709,4.2557871 c -0.3126291,0 -0.4819578,0.1287194 -0.5322266,0.4028321 -0.053173,0.2899914 0.1062609,0.5159057 0.4370117,0.6274414 1.420521,0.4790277 2.4256503,0.6675279 3.8410483,0.9800416 0.327839,0.072385 0.6900295,0.2893751 0.6520998,1.0948483 C 6.6985575,8.451345 6.6372144,9.7041167 6.2631031,11.323353 6.0397526,12.290062 5.6782112,13.622766 5.4305838,14.3922 5.3416728,14.668443 5.281658,14.922355 5.281658,15.031849 c 0,0.08257 0.053443,0.249642 0.097656,0.307617 0.023823,0.03125 0.075039,0.07397 0.1147462,0.09522 0.062879,0.03361 0.096262,0.03787 0.2612304,0.03663 0.3361373,-0.0026 0.4608113,-0.08245 0.6665037,-0.429687 0.4838657,-0.939315 0.7378785,-2.132191 0.9402993,-3.014266 0.092189,-0.517235 0.2624476,-1.66347 0.6710287,-1.66347 0.4085811,0 0.4979093,0.95008 0.6812062,1.687228 0.1832969,0.737148 0.6122738,2.295202 0.7738717,2.704862 0.2137476,0.54186 0.5742238,0.836985 0.8764648,0.717774 0.03316,-0.01301 0.116937,-0.04526 0.187989,-0.0708 0.147435,-0.053 0.186715,-0.07824 0.219726,-0.156249 0.0655,-0.154793 -0.01013,-0.454047 -0.349121,-1.41114 C 9.7721847,11.597192 9.2651806,9.3990255 9.3334308,7.2974743 9.3630343,6.3859259 9.6837054,6.305369 10.075725,6.2075087 c 1.17285,-0.2927798 2.00228,-0.379973 3.387085,-0.8579717 0.468513,-0.1617184 0.727539,-0.2608264 0.727539,-0.5590819 0,-0.2554049 -0.153084,-0.4346541 -0.437011,-0.5102538 -0.116851,-0.031101 -0.318383,-0.028905 -0.632326,0.00243 -1.085189,0.10834 -2.939683,0.5153868 -4.0234365,0.6710819 -0.529944,0.076133 -1.7229392,0.094015 -2.2729489,0 C 5.6763224,4.7574297 4.1363176,4.4147025 2.9061699,4.2997326 2.6560099,4.2763537 2.4068766,4.2557871 2.3519709,4.2557871 Z"
style="fill:#000000;stroke-width:0.9048177" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.0 KiB

-76
View File
@@ -1,76 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg2"
width="16"
height="16"
viewBox="0 0 16 16"
sodipodi:docname="app.svg"
inkscape:version="0.92.2 5c3e80d, 2017-08-06">
<metadata
id="metadata8">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1880"
inkscape:window-height="993"
id="namedview4"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
inkscape:zoom="36.460193"
inkscape:cx="8.4752826"
inkscape:cy="18.273624"
inkscape:window-x="20"
inkscape:window-y="67"
inkscape:window-maximized="0"
inkscape:current-layer="g848"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<g
id="g848"
transform="matrix(1.1307959,0,0,1.0801738,-1.0463882,-0.84269722)"
style="stroke-width:0.90481776;fill:#000000">
<circle
r="1.9587879"
cy="2.8315151"
cx="7.990303"
id="path844"
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.90481776;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke markers fill" />
<path
sodipodi:nodetypes="scsssscsccccczzcccccssssccsscs"
inkscape:connector-curvature="0"
id="path843"
d="m 2.3519709,4.2557871 c -0.3126291,0 -0.4819578,0.1287194 -0.5322266,0.4028321 -0.053173,0.2899914 0.1062609,0.5159057 0.4370117,0.6274414 1.420521,0.4790277 2.4256503,0.6675279 3.8410483,0.9800416 0.327839,0.072385 0.6900295,0.2893751 0.6520998,1.0948483 C 6.6985575,8.451345 6.6372144,9.7041167 6.2631031,11.323353 6.0397526,12.290062 5.6782112,13.622766 5.4305838,14.3922 5.3416728,14.668443 5.281658,14.922355 5.281658,15.031849 c 0,0.08257 0.053443,0.249642 0.097656,0.307617 0.023823,0.03125 0.075039,0.07397 0.1147462,0.09522 0.062879,0.03361 0.096262,0.03787 0.2612304,0.03663 0.3361373,-0.0026 0.4608113,-0.08245 0.6665037,-0.429687 0.4838657,-0.939315 0.7378785,-2.132191 0.9402993,-3.014266 0.092189,-0.517235 0.2624476,-1.66347 0.6710287,-1.66347 0.4085811,0 0.4979093,0.95008 0.6812062,1.687228 0.1832969,0.737148 0.6122738,2.295202 0.7738717,2.704862 0.2137476,0.54186 0.5742238,0.836985 0.8764648,0.717774 0.03316,-0.01301 0.116937,-0.04526 0.187989,-0.0708 0.147435,-0.053 0.186715,-0.07824 0.219726,-0.156249 0.0655,-0.154793 -0.01013,-0.454047 -0.349121,-1.41114 C 9.7721847,11.597192 9.2651806,9.3990255 9.3334308,7.2974743 9.3630343,6.3859259 9.6837054,6.305369 10.075725,6.2075087 c 1.17285,-0.2927798 2.00228,-0.379973 3.387085,-0.8579717 0.468513,-0.1617184 0.727539,-0.2608264 0.727539,-0.5590819 0,-0.2554049 -0.153084,-0.4346541 -0.437011,-0.5102538 -0.116851,-0.031101 -0.318383,-0.028905 -0.632326,0.00243 -1.085189,0.10834 -2.939683,0.5153868 -4.0234365,0.6710819 -0.529944,0.076133 -1.7229392,0.094015 -2.2729489,0 C 5.6763224,4.7574297 4.1363176,4.4147025 2.9061699,4.2997326 2.6560099,4.2763537 2.4068766,4.2557871 2.3519709,4.2557871 Z"
style="fill:#ffffff;stroke-width:0.9048177" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,83 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Accessibility;
use OCP\IL10N;
use OCP\IURLGenerator;
class AccessibilityProvider {
/** @var string */
protected $appName;
/** @var IURLGenerator */
private $urlGenerator;
/** @var IL10N */
private $l;
/**
* Account constructor.
*
* @param string $appName
* @param IURLGenerator $urlGenerator
* @param IL10N $l
*/
public function __construct(string $appName,
IURLGenerator $urlGenerator,
IL10N $l) {
$this->appName = $appName;
$this->urlGenerator = $urlGenerator;
$this->l = $l;
}
public function getThemes() {
return array(
[
'id' => 'themehighcontrast',
'img' => $this->urlGenerator->imagePath($this->appName, 'theme-highcontrast.jpg'),
'title' => $this->l->t('High contrast theme'),
'text' => $this->l->t('A high contrast theme to ease your navigation. Visual quality will be reduced but clarity will be increased.')
], [
'id' => 'themedark',
'img' => $this->urlGenerator->imagePath($this->appName, 'theme-dark.jpg'),
'title' => $this->l->t('Dark theme (beta)'),
'text' => $this->l->t('A dark theme to ease your eyes by reducing the overall luminosity and brightness. It is still under development, so please report any issues you may find.')
]
);
}
public function getFonts() {
return array(
[
'id' => 'fontdyslexic',
'img' => $this->urlGenerator->imagePath($this->appName, 'font-opendyslexic.jpg'),
'title' => $this->l->t('Dyslexia font'),
'text' => $this->l->t('OpenDyslexic is a free typeface/font designed to mitigate some of the common reading errors caused by dyslexia. The typeface was created by Abelardo Gonzalez, who released it through an open-source license.')
]
);
}
}
@@ -1,65 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Accessibility\AppInfo;
use OCP\AppFramework\App;
use OCP\IConfig;
use OCP\IUserSession;
use OCP\IURLGenerator;
class Application extends App {
/** @var string */
protected $appName = 'accessibility';
/** @var IConfig */
private $config;
/** @var IUserSession */
private $userSession;
/** @var IURLGenerator */
private $urlGenerator;
public function __construct() {
parent::__construct($this->appName);
$this->config = \OC::$server->getConfig();
$this->userSession = \OC::$server->getUserSession();
$this->urlGenerator = \OC::$server->getURLGenerator();
}
public function injectCss() {
// Inject the fake css on all pages if enabled and user is logged
$loggedUser = $this->userSession->getUser();
if (!is_null($loggedUser)) {
$userValues = $this->config->getUserKeys($loggedUser->getUID(), $this->appName);
// we want to check if any theme or font is enabled.
if (count($userValues) > 0) {
$hash = $this->config->getUserValue($loggedUser->getUID(), $this->appName, 'icons-css', md5(implode('-', $userValues)));
$linkToCSS = $this->urlGenerator->linkToRoute($this->appName . '.accessibility.getCss', ['md5' => $hash]);
\OCP\Util::addHeader('link', ['rel' => 'stylesheet', 'href' => $linkToCSS]);
}
}
}
}
@@ -1,259 +0,0 @@
<?php
declare (strict_types = 1);
/**
* @copyright Copyright (c) 2018 John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Accessibility\Controller;
use Leafo\ScssPhp\Compiler;
use Leafo\ScssPhp\Exception\ParserException;
use Leafo\ScssPhp\Formatter\Crunched;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataDisplayResponse;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\App\IAppManager;
use OCP\IConfig;
use OCP\ILogger;
use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\IUserManager;
use OCP\IUserSession;
use OC\Template\IconsCacher;
class AccessibilityController extends Controller {
/** @var string */
protected $appName;
/** @var string */
protected $serverRoot;
/** @var IConfig */
private $config;
/** @var IUserManager */
private $userManager;
/** @var ILogger */
private $logger;
/** @var IURLGenerator */
private $urlGenerator;
/** @var ITimeFactory */
protected $timeFactory;
/** @var IUserSession */
private $userSession;
/** @var IAppManager */
private $appManager;
/** @var IconsCacher */
protected $iconsCacher;
/** @var \OC_Defaults */
private $defaults;
/** @var null|string */
private $injectedVariables;
/**
* Account constructor.
*
* @param string $appName
* @param IRequest $request
* @param IConfig $config
* @param IUserManager $userManager
* @param ILogger $logger
* @param IURLGenerator $urlGenerator
* @param ITimeFactory $timeFactory
* @param IUserSession $userSession
* @param IAppManager $appManager
* @param \OC_Defaults $defaults
*/
public function __construct(string $appName,
IRequest $request,
IConfig $config,
IUserManager $userManager,
ILogger $logger,
IURLGenerator $urlGenerator,
ITimeFactory $timeFactory,
IUserSession $userSession,
IAppManager $appManager,
IconsCacher $iconsCacher,
\OC_Defaults $defaults) {
parent::__construct($appName, $request);
$this->appName = $appName;
$this->config = $config;
$this->userManager = $userManager;
$this->logger = $logger;
$this->urlGenerator = $urlGenerator;
$this->timeFactory = $timeFactory;
$this->userSession = $userSession;
$this->appManager = $appManager;
$this->iconsCacher = $iconsCacher;
$this->defaults = $defaults;
$this->serverRoot = \OC::$SERVERROOT;
$this->appRoot = $this->appManager->getAppPath($this->appName);
}
/**
* @NoAdminRequired
* @NoCSRFRequired
*
* @return DataDisplayResponse
*/
public function getCss(): DataDisplayResponse {
$css = '';
$imports = '';
$userValues = $this->getUserValues();
foreach ($userValues as $key => $scssFile) {
if ($scssFile !== false) {
$imports .= '@import "' . $scssFile . '";';
}
}
if ($imports !== '') {
$scss = new Compiler();
$scss->setImportPaths([
$this->appRoot . '/css/',
$this->serverRoot . '/core/css/'
]);
// Continue after throw
$scss->setIgnoreErrors(true);
$scss->setFormatter(Crunched::class);
// Import theme, variables and compile css4 variables
try {
$css .= $scss->compile(
$imports .
$this->getInjectedVariables() .
'@import "variables.scss";' .
'@import "css-variables.scss";'
);
} catch (ParserException $e) {
$this->logger->error($e->getMessage(), ['app' => 'core']);
}
}
// We don't want to override vars with url since path is different
$css = $this->filterOutRule('/--[a-z-:]+url\([^;]+\)/mi', $css);
// Rebase all urls
$appWebRoot = substr($this->appRoot, strlen($this->serverRoot) - strlen(\OC::$WEBROOT));
$css = $this->rebaseUrls($css, $appWebRoot . '/css');
if (in_array('themedark', $userValues) && $this->iconsCacher->getCachedCSS() && $this->iconsCacher->getCachedCSS()->getSize() > 0) {
$iconsCss = $this->invertSvgIconsColor($this->iconsCacher->getCachedCSS()->getContent());
$css = $css . $iconsCss;
}
$response = new DataDisplayResponse($css, Http::STATUS_OK, ['Content-Type' => 'text/css']);
// Set cache control
$ttl = 31536000;
$response->addHeader('Cache-Control', 'max-age=' . $ttl . ', immutable');
$expires = new \DateTime();
$expires->setTimestamp($this->timeFactory->getTime());
$expires->add(new \DateInterval('PT' . $ttl . 'S'));
$response->addHeader('Expires', $expires->format(\DateTime::RFC1123));
$response->addHeader('Pragma', 'cache');
// store current cache hash
$this->config->setUserValue($this->userSession->getUser()->getUID(), $this->appName, 'icons-css', md5($css));
return $response;
}
/**
* Return an array with the user theme & font settings
*
* @return array
*/
private function getUserValues(): array{
$userTheme = $this->config->getUserValue($this->userSession->getUser()->getUID(), $this->appName, 'theme', false);
$userFont = $this->config->getUserValue($this->userSession->getUser()->getUID(), $this->appName, 'font', false);
return [$userTheme, $userFont];
}
/**
* Remove all matches from the $rule regex
*
* @param string $rule regex to match
* @param string $css string to parse
* @return string
*/
private function filterOutRule(string $rule, string $css): string {
return preg_replace($rule, '', $css);
}
/**
* Add the correct uri prefix to make uri valid again
*
* @param string $css
* @param string $webDir
* @return string
*/
private function rebaseUrls(string $css, string $webDir): string {
$re = '/url\([\'"]([^\/][\.\w?=\/-]*)[\'"]\)/x';
$subst = 'url(\'' . $webDir . '/$1\')';
return preg_replace($re, $subst, $css);
}
/**
* Remove all matches from the $rule regex
*
* @param string $css string to parse
* @return string
*/
private function invertSvgIconsColor(string $css) {
return str_replace(['/000', '/fff', '/***'], ['/***', '/000', '/fff'], $css);
}
/**
* @return string SCSS code for variables from OC_Defaults
*/
private function getInjectedVariables(): string {
if ($this->injectedVariables !== null) {
return $this->injectedVariables;
}
$variables = '';
foreach ($this->defaults->getScssVariables() as $key => $value) {
$variables .= '$' . $key . ': ' . $value . ';';
}
// check for valid variables / otherwise fall back to defaults
try {
$scss = new Compiler();
$scss->compile($variables);
$this->injectedVariables = $variables;
} catch (ParserException $e) {
$this->logger->error($e, ['app' => 'core']);
}
return $variables;
}
}
@@ -1,133 +0,0 @@
<?php
declare (strict_types = 1);
/**
* @copyright Copyright (c) 2018 John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Accessibility\Controller;
use OCA\Accessibility\AccessibilityProvider;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\AppFramework\OCS\OCSBadRequestException;
use OCP\IConfig;
use OCP\IRequest;
use OCP\IUserSession;
class ConfigController extends OCSController {
/** @var string */
protected $appName;
/** @var string */
protected $userId;
/** @var string */
protected $serverRoot;
/** @var IConfig */
private $config;
/** @var IUserSession */
private $userSession;
/** @var AccessibilityProvider */
private $accessibilityProvider;
/**
* Config constructor.
*
* @param string $appName
* @param IRequest $request
* @param IConfig $config
* @param IUserSession $userSession
* @param AccessibilityProvider $accessibilityProvider
*/
public function __construct(string $appName,
IRequest $request,
IConfig $config,
IUserSession $userSession,
AccessibilityProvider $accessibilityProvider) {
parent::__construct($appName, $request);
$this->appName = $appName;
$this->config = $config;
$this->userSession = $userSession;
$this->accessibilityProvider = $accessibilityProvider;
$this->userId = $userSession->getUser()->getUID();
}
/**
* @NoAdminRequired
*
* Get user accessibility config
*
* @param string $key theme or font
* @return DataResponse
*/
public function getConfig(): DataResponse {
return new DataResponse([
'theme' => $this->config->getUserValue($this->userId, $this->appName, 'theme', false),
'font' => $this->config->getUserValue($this->userId, $this->appName, 'font', false)
]);
}
/**
* @NoAdminRequired
*
* Set theme or font config
*
* @param string $key theme or font
* @return DataResponse
* @throws Exception
*/
public function setConfig(string $key, $value): DataResponse {
if ($key === 'theme' || $key === 'font') {
if ($value === false) {
$this->config->deleteUserValue($this->userId, $this->appName, $key);
$userValues = $this->config->getUserKeys($this->userId, $this->appName);
// remove hash if no settings selected
if (count($userValues) === 1 && $userValues[0] === 'icons-css') {
$this->config->deleteUserValue($this->userId, $this->appName, 'icons-css');
}
return new DataResponse();
}
$themes = $this->accessibilityProvider->getThemes();
$fonts = $this->accessibilityProvider->getFonts();
$availableOptions = array_map(function($option) {
return $option['id'];
}, array_merge($themes, $fonts));
if (in_array($value, $availableOptions)) {
$this->config->setUserValue($this->userId, $this->appName, $key, $value);
return new DataResponse();
}
throw new OCSBadRequestException('Invalid value: ' . $value);
}
throw new OCSBadRequestException('Invalid key: ' . $key);
}
}
@@ -1,113 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Accessibility\Settings;
use OCA\Accessibility\AccessibilityProvider;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IConfig;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\IUserSession;
use OCP\Settings\ISettings;
class Personal implements ISettings {
/** @var string */
protected $appName;
/** @var IConfig */
private $config;
/** @var IUserSession */
private $userSession;
/** @var IL10N */
private $l;
/** @var IURLGenerator */
private $urlGenerator;
/** @var AccessibilityProvider */
private $accessibilityProvider;
/**
* Settings constructor.
*
* @param string $appName
* @param IConfig $config
* @param IUserSession $userSession
* @param IL10N $l
* @param IURLGenerator $urlGenerator
* @param AccessibilityProvider $accessibilityProvider
*/
public function __construct(string $appName,
IConfig $config,
IUserSession $userSession,
IL10N $l,
IURLGenerator $urlGenerator,
AccessibilityProvider $accessibilityProvider) {
$this->appName = $appName;
$this->config = $config;
$this->userSession = $userSession;
$this->l = $l;
$this->urlGenerator = $urlGenerator;
$this->accessibilityProvider = $accessibilityProvider;
}
/**
* @return TemplateResponse returns the instance with all parameters set, ready to be rendered
* @since 9.1
*/
public function getForm() {
$serverData = [
'themes' => $this->accessibilityProvider->getThemes(),
'fonts' => $this->accessibilityProvider->getFonts(),
'theme' => $this->config->getUserValue($this->userSession->getUser()->getUID(), $this->appName, 'theme', false),
'font' => $this->config->getUserValue($this->userSession->getUser()->getUID(), $this->appName, 'font', false)
];
return new TemplateResponse($this->appName, 'settings-personal', ['serverData' => $serverData]);
}
/**
* @return string the section ID, e.g. 'sharing'
* @since 9.1
*/
public function getSection() {
return $this->appName;
}
/**
* @return int whether the form should be rather on the top or bottom of
* the admin section. The forms are arranged in ascending order of the
* priority values. It is required to return a value between 0 and 100.
*
* E.g.: 70
* @since 9.1
*/
public function getPriority() {
return 40;
}
}
@@ -1,100 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Accessibility\Settings;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\Settings\IIconSection;
class PersonalSection implements IIconSection {
/** @var string */
protected $appName;
/** @var IURLGenerator */
private $urlGenerator;
/** @var IL10N */
private $l;
/**
* Personal Section constructor.
*
* @param string $appName
* @param IURLGenerator $urlGenerator
* @param IL10N $l
*/
public function __construct(string $appName,
IURLGenerator $urlGenerator,
IL10N $l) {
$this->appName = $appName;
$this->urlGenerator = $urlGenerator;
$this->l = $l;
}
/**
* returns the relative path to an 16*16 icon describing the section.
* e.g. '/core/img/places/files.svg'
*
* @returns string
* @since 13.0.0
*/
public function getIcon() {
return $this->urlGenerator->imagePath($this->appName, 'app-dark.svg');
}
/**
* returns the ID of the section. It is supposed to be a lower case string,
* e.g. 'ldap'
*
* @returns string
* @since 9.1
*/
public function getID() {
return $this->appName;
}
/**
* returns the translated name as it should be displayed, e.g. 'LDAP / AD
* integration'. Use the L10N service to translate it.
*
* @return string
* @since 9.1
*/
public function getName() {
return $this->l->t('Accessibility');
}
/**
* @return int whether the form should be rather on the top or bottom of
* the settings navigation. The sections are arranged in ascending order of
* the priority values. It is required to return a value between 0 and 99.
*
* E.g.: 70
* @since 9.1
*/
public function getPriority() {
return 15;
}
}
File diff suppressed because it is too large Load Diff
-33
View File
@@ -1,33 +0,0 @@
{
"name": "accessibility",
"description": "Provides multiple accessibilities options to ease your use of nextcloud",
"version": "1.0.2",
"author": "John Molakvoæ <skjnldsv@protonmail.com>",
"license": "agpl",
"private": true,
"scripts": {
"dev": "webpack --config webpack.dev.js",
"watch": "webpack --progress --watch --config webpack.dev.js",
"build": "webpack --progress --hide-modules --config webpack.prod.js"
},
"dependencies": {
"axios": "^0.18.1",
"vue": "^2.5.16"
},
"browserslist": [
"last 2 versions",
"not ie <= 11"
],
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^7.1.5",
"babel-preset-env": "^1.7.0",
"css-loader": "^1.0.0",
"file-loader": "^1.1.11",
"vue-loader": "^15.2.6",
"vue-template-compiler": "^2.5.16",
"webpack": "^4.16.1",
"webpack-cli": "^3.1.0",
"webpack-merge": "^4.1.3"
}
}
-116
View File
@@ -1,116 +0,0 @@
<template>
<div id="accessibility">
<div id="themes" class="section">
<h2>{{t('accessibility', 'Themes')}}</h2>
<div class="themes-list preview-list">
<preview v-for="preview in themes" :preview="preview"
:key="preview.id" :selected="selected.theme"
v-on:select="selectTheme"></preview>
</div>
</div>
<div id="fonts" class="section">
<h2>{{t('accessibility', 'Fonts')}}</h2>
<div class="fonts-list preview-list">
<preview v-for="preview in fonts" :preview="preview"
:key="preview.id" :selected="selected.font"
v-on:select="selectFont"></preview>
</div>
</div>
</div>
</template>
<script>
import preview from './components/itemPreview';
import axios from 'axios';
export default {
name: 'Accessibility',
components: { preview },
beforeMount() {
// importing server data into the app
const serverDataElmt = document.getElementById('serverData');
if (serverDataElmt !== null) {
this.serverData = JSON.parse(
document.getElementById('serverData').dataset.server
);
}
},
data() {
return {
serverData: []
};
},
computed: {
themes() {
return this.serverData.themes;
},
fonts() {
return this.serverData.fonts;
},
selected() {
return {
theme: this.serverData.theme,
font: this.serverData.font
};
},
tokenHeaders() {
return { headers: { requesttoken: OC.requestToken } };
}
},
methods: {
selectTheme(id) {
this.selectItem('theme', id);
},
selectFont(id) {
this.selectItem('font', id);
},
/**
* Commit a change and force reload css
* Fetching the file again will trigger the server update
*
* @param {string} type type of the change (font or theme)
* @param {string} id the data of the change
*/
selectItem(type, id) {
axios.post(
OC.linkToOCS('apps/accessibility/api/v1/config', 2) + type,
{ value: id },
this.tokenHeaders
)
.then(response => {
this.serverData[type] = id;
// Remove old link
let link = document.querySelector('link[rel=stylesheet][href*=accessibility][href*=user-]');
if (!link) {
// insert new css
let link = document.createElement('link');
link.rel = 'stylesheet';
link.href = OC.generateUrl('/apps/accessibility/css/user-style.css') + '?v=' + new Date().getTime();
document.head.appendChild(link);
} else {
// compare arrays
if (
JSON.stringify(Object.values(this.selected)) ===
JSON.stringify([false, false])
) {
// if nothing is selected, blindly remove the css
link.remove();
} else {
// force update
link.href =
link.href.split('?')[0] +
'?v=' +
new Date().getTime();
}
}
})
.catch(err => {
console.log(err, err.response);
OC.Notification.showTemporary(t('accessibility', err.response.data.ocs.meta.message + '. Unable to apply the setting.'));
});
}
}
};
</script>
@@ -1,27 +0,0 @@
<template>
<a :class="{preview: true, selected: preview.id === selected}"
href="#" @click="selectItem">
<div class="preview-image" :style="{backgroundImage: 'url(' + preview.img + ')'}"></div>
<h3>
<span>{{preview.title}}</span>
<div class="icon-checkmark-color">{{t('accessibility', 'enabled')}}</div>
</h3>
<p>{{preview.text}}</p>
</a>
</template>
<script>
export default {
name: 'itemPreview',
props: ['preview', 'selected'],
methods: {
selectItem() {
this.$emit(
'select',
// if we clicked the already selected one: disable it
this.preview.id === this.selected ? false : this.preview.id
);
}
}
};
</script>
-12
View File
@@ -1,12 +0,0 @@
import Vue from 'vue';
import App from './App.vue';
/* global t */
// bind to window
Vue.prototype.OC = OC;
Vue.prototype.t = t;
new Vue({
el: '#accessibility',
render: h => h(App)
});
@@ -1,29 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
script('accessibility', 'accessibility');
style('accessibility', 'style');
?>
<span id="serverData" data-server="<?php p(json_encode($_['serverData']));?>"></span>
<span id="accessibility"></span>
-42
View File
@@ -1,42 +0,0 @@
const path = require('path');
const { VueLoaderPlugin } = require('vue-loader');
module.exports = {
entry: path.join(__dirname, 'src', 'main.js'),
output: {
path: path.resolve(__dirname, './js'),
publicPath: '/js/',
filename: 'accessibility.js'
},
module: {
rules: [
{
test: /\.css$/,
use: ['vue-style-loader', 'css-loader']
},
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
plugins: [new VueLoaderPlugin()],
resolve: {
alias: {
vue$: 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
}
};
-12
View File
@@ -1,12 +0,0 @@
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
devtool: '#eval-source-map'
});
-7
View File
@@ -1,7 +0,0 @@
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
devtool: '#source-map'
});
-1
View File
@@ -1,5 +1,4 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
* @copyright Copyright (c) 2017 Lukas Reschke <lukas@statuscode.ch>
+6 -13
View File
@@ -1,23 +1,16 @@
<?xml version="1.0"?>
<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
<info>
<id>admin_audit</id>
<name>Auditing / Logging</name>
<summary>Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions.</summary>
<description>Provides logging abilities for Nextcloud such as logging file accesses or otherwise sensitive actions.</description>
<version>1.4.0</version>
<licence>agpl</licence>
<licence>AGPL</licence>
<author>Nextcloud</author>
<version>1.3.0</version>
<namespace>AdminAudit</namespace>
<dependencies>
<nextcloud min-version="13" max-version="13" />
</dependencies>
<types>
<logging/>
</types>
<category>monitoring</category>
<bugs>https://github.com/nextcloud/server/issues</bugs>
<dependencies>
<nextcloud min-version="14" max-version="14" />
</dependencies>
<background-jobs>
<job>OCA\AdminAudit\BackgroundJobs\Rotate</job>
</background-jobs>
</info>
@@ -43,7 +43,8 @@ namespace Composer\Autoload;
class ClassLoader
{
// PSR-4
private $prefixLengthsPsr4 = array();
private $firstCharsPsr4 = array();
private $prefixLengthsPsr4 = array(); // For BC with legacy static maps
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
@@ -170,11 +171,10 @@ class ClassLoader
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
if ('\\' !== substr($prefix, -1)) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->firstCharsPsr4[$prefix[0]] = true;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
@@ -221,11 +221,10 @@ class ClassLoader
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
if ('\\' !== substr($prefix, -1)) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->firstCharsPsr4[$prefix[0]] = true;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
@@ -279,7 +278,7 @@ class ClassLoader
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
}
/**
@@ -373,11 +372,11 @@ class ClassLoader
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
if (isset($this->firstCharsPsr4[$first]) || isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
$search = $subPath.'\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
@@ -12,11 +12,9 @@ return array(
'OCA\\AdminAudit\\Actions\\Console' => $baseDir . '/../lib/Actions/Console.php',
'OCA\\AdminAudit\\Actions\\Files' => $baseDir . '/../lib/Actions/Files.php',
'OCA\\AdminAudit\\Actions\\GroupManagement' => $baseDir . '/../lib/Actions/GroupManagement.php',
'OCA\\AdminAudit\\Actions\\Security' => $baseDir . '/../lib/Actions/Security.php',
'OCA\\AdminAudit\\Actions\\Sharing' => $baseDir . '/../lib/Actions/Sharing.php',
'OCA\\AdminAudit\\Actions\\Trashbin' => $baseDir . '/../lib/Actions/Trashbin.php',
'OCA\\AdminAudit\\Actions\\UserManagement' => $baseDir . '/../lib/Actions/UserManagement.php',
'OCA\\AdminAudit\\Actions\\Versions' => $baseDir . '/../lib/Actions/Versions.php',
'OCA\\AdminAudit\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php',
'OCA\\AdminAudit\\BackgroundJobs\\Rotate' => $baseDir . '/../lib/BackgroundJobs/Rotate.php',
);
@@ -6,11 +6,8 @@ namespace Composer\Autoload;
class ComposerStaticInitAdminAudit
{
public static $prefixLengthsPsr4 = array (
'O' =>
array (
'OCA\\AdminAudit\\' => 15,
),
public static $firstCharsPsr4 = array (
'O' => true,
);
public static $prefixDirsPsr4 = array (
@@ -27,19 +24,17 @@ class ComposerStaticInitAdminAudit
'OCA\\AdminAudit\\Actions\\Console' => __DIR__ . '/..' . '/../lib/Actions/Console.php',
'OCA\\AdminAudit\\Actions\\Files' => __DIR__ . '/..' . '/../lib/Actions/Files.php',
'OCA\\AdminAudit\\Actions\\GroupManagement' => __DIR__ . '/..' . '/../lib/Actions/GroupManagement.php',
'OCA\\AdminAudit\\Actions\\Security' => __DIR__ . '/..' . '/../lib/Actions/Security.php',
'OCA\\AdminAudit\\Actions\\Sharing' => __DIR__ . '/..' . '/../lib/Actions/Sharing.php',
'OCA\\AdminAudit\\Actions\\Trashbin' => __DIR__ . '/..' . '/../lib/Actions/Trashbin.php',
'OCA\\AdminAudit\\Actions\\UserManagement' => __DIR__ . '/..' . '/../lib/Actions/UserManagement.php',
'OCA\\AdminAudit\\Actions\\Versions' => __DIR__ . '/..' . '/../lib/Actions/Versions.php',
'OCA\\AdminAudit\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php',
'OCA\\AdminAudit\\BackgroundJobs\\Rotate' => __DIR__ . '/..' . '/../lib/BackgroundJobs/Rotate.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitAdminAudit::$prefixLengthsPsr4;
$loader->firstCharsPsr4 = ComposerStaticInitAdminAudit::$firstCharsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitAdminAudit::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitAdminAudit::$classMap;
+2 -3
View File
@@ -1,5 +1,4 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
*
@@ -46,10 +45,10 @@ class Action {
* @param array $elements
* @param bool $obfuscateParameters
*/
public function log(string $text,
public function log($text,
array $params,
array $elements,
bool $obfuscateParameters = false) {
$obfuscateParameters = false) {
foreach($elements as $element) {
if(!isset($params[$element])) {
if ($obfuscateParameters) {
@@ -1,5 +1,4 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com>
*
@@ -29,7 +28,7 @@ class AppManagement extends Action {
/**
* @param string $appName
*/
public function enableApp(string $appName) {
public function enableApp($appName) {
$this->log('App "%s" enabled',
['app' => $appName],
['app']
@@ -40,7 +39,7 @@ class AppManagement extends Action {
* @param string $appName
* @param string[] $groups
*/
public function enableAppForGroups(string $appName, array $groups) {
public function enableAppForGroups($appName, array $groups) {
$this->log('App "%s" enabled for groups: %s',
['app' => $appName, 'groups' => implode(', ', $groups)],
['app', 'groups']
@@ -50,7 +49,7 @@ class AppManagement extends Action {
/**
* @param string $appName
*/
public function disableApp(string $appName) {
public function disableApp($appName) {
$this->log('App "%s" disabled',
['app' => $appName],
['app']
-1
View File
@@ -1,5 +1,4 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
*
+1 -2
View File
@@ -1,5 +1,4 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com>
*
@@ -29,7 +28,7 @@ class Console extends Action {
/**
* @param $arguments
*/
public function runCommand(array $arguments) {
public function runCommand($arguments) {
if ($arguments[1] === '_completion') {
// Don't log autocompletion
return;
-1
View File
@@ -1,5 +1,4 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
*
@@ -1,5 +1,4 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
-75
View File
@@ -1,75 +0,0 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\AdminAudit\Actions;
use OCP\IUser;
/**
* Class Sharing logs the sharing actions
*
* @package OCA\AdminAudit\Actions
*/
class Security extends Action {
/**
* Log twofactor auth enabled
*
* @param IUser $user
* @param array $params
*/
public function twofactorFailed(IUser $user, array $params) {
$params['uid'] = $user->getUID();
$params['displayName'] = $user->getDisplayName();
$this->log(
'Failed two factor attempt by user %s (%s) with provider %s',
$params,
[
'displayName',
'uid',
'provider',
]
);
}
/**
* Logs unsharing of data
*
* @param IUser $user
* @param array $params
*/
public function twofactorSuccess(IUser $user, array $params) {
$params['uid'] = $user->getUID();
$params['displayName'] = $user->getDisplayName();
$this->log(
'Successful two factor attempt by user %s (%s) with provider %s',
$params,
[
'displayName',
'uid',
'provider',
]
);
}
}
-26
View File
@@ -1,5 +1,4 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
*
@@ -78,19 +77,6 @@ class Sharing extends Action {
'id',
]
);
} elseif($params['shareType'] === Share::SHARE_TYPE_ROOM) {
$this->log(
'The %s "%s" with ID "%s" has been shared to the room "%s" with permissions "%s" (Share ID: %s)',
$params,
[
'itemType',
'itemTarget',
'itemSource',
'shareWith',
'permissions',
'id',
]
);
}
}
@@ -135,18 +121,6 @@ class Sharing extends Action {
'id',
]
);
} elseif($params['shareType'] === Share::SHARE_TYPE_ROOM) {
$this->log(
'The %s "%s" with ID "%s" has been unshared from the room "%s" (Share ID: %s)',
$params,
[
'itemType',
'fileTarget',
'itemSource',
'shareWith',
'id',
]
);
}
}
+2 -3
View File
@@ -1,5 +1,4 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org>
*
@@ -28,13 +27,13 @@ namespace OCA\AdminAudit\Actions;
class Trashbin extends Action {
public function delete(array $params) {
public function delete($params) {
$this->log('File "%s" deleted from trash bin.',
['path' => $params['path']], ['path']
);
}
public function restore(array $params) {
public function restore($params) {
$this->log('File "%s" restored from trash bin.',
['path' => $params['filePath']], ['path']
);
@@ -1,5 +1,4 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch>
*
@@ -50,19 +49,6 @@ class UserManagement extends Action {
);
}
/**
* Log assignments of users (typically user backends)
*
* @param string $uid
*/
public function assign(string $uid) {
$this->log(
'UserID assigned: "%s"',
[ 'uid' => $uid ],
[ 'uid' ]
);
}
/**
* Log deletion of users
*
@@ -78,44 +64,20 @@ class UserManagement extends Action {
);
}
/**
* Log unassignments of users (typically user backends, no data removed)
*
* @param string $uid
*/
public function unassign(string $uid) {
$this->log(
'UserID unassigned: "%s"',
[ 'uid' => $uid ],
[ 'uid' ]
);
}
/**
* Log enabling of users
*
* @param array $params
*/
public function change(array $params) {
switch($params['feature']) {
case 'enabled':
$this->log(
$params['value'] === 'true' ? 'User enabled: "%s"' : 'User disabled: "%s"',
['user' => $params['user']->getUID()],
[
'user',
]
);
break;
case 'eMailAddress':
$this->log(
'Email address changed for user %s',
['user' => $params['user']->getUID()],
[
'user',
]
);
break;
if ($params['feature'] === 'enabled') {
$this->log(
$params['value'] === 'true' ? 'User enabled: "%s"' : 'User disabled: "%s"',
['user' => $params['user']->getUID()],
[
'user',
]
);
}
}
+2 -3
View File
@@ -1,5 +1,4 @@
<?php
declare(strict_types=1);
/**
* @copyright Bjoern Schiessle <bjoern@schiessle.org>
*
@@ -28,7 +27,7 @@ namespace OCA\AdminAudit\Actions;
class Versions extends Action {
public function rollback(array $params) {
public function rollback($params) {
$this->log('Version "%s" of "%s" was restored.',
[
'version' => $params['revision'],
@@ -38,7 +37,7 @@ class Versions extends Action {
);
}
public function delete(array $params) {
public function delete($params) {
$this->log('Version "%s" was deleted.',
['path' => $params['path']],
['path']
+40 -76
View File
@@ -1,5 +1,4 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2017 Joas Schilling <coding@schilljs.com>
*
@@ -34,14 +33,12 @@ use OCA\AdminAudit\Actions\Auth;
use OCA\AdminAudit\Actions\Console;
use OCA\AdminAudit\Actions\Files;
use OCA\AdminAudit\Actions\GroupManagement;
use OCA\AdminAudit\Actions\Security;
use OCA\AdminAudit\Actions\Sharing;
use OCA\AdminAudit\Actions\Trashbin;
use OCA\AdminAudit\Actions\UserManagement;
use OCA\AdminAudit\Actions\Versions;
use OCP\App\ManagerEvent;
use OCP\AppFramework\App;
use OCP\Authentication\TwoFactorAuth\IProvider;
use OCP\Console\ConsoleEvent;
use OCP\IGroupManager;
use OCP\ILogger;
@@ -49,30 +46,11 @@ use OCP\IPreview;
use OCP\IUserSession;
use OCP\Util;
use Symfony\Component\EventDispatcher\GenericEvent;
use OCP\Share;
class Application extends App {
/** @var ILogger */
protected $logger;
public function __construct() {
parent::__construct('admin_audit');
$this->initLogger();
}
public function initLogger() {
$c = $this->getContainer()->getServer();
$config = $c->getConfig();
$default = $config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/audit.log';
$logFile = $config->getAppValue('admin_audit', 'logfile', $default);
if($logFile === null) {
$this->logger = $c->getLogger();
return;
}
$this->logger = $c->getLogFactory()->getCustomLogger($logFile);
}
public function register() {
@@ -83,24 +61,24 @@ class Application extends App {
* Register hooks in order to log them
*/
protected function registerHooks() {
$this->userManagementHooks();
$this->groupHooks();
$this->authHooks();
$logger = $this->getContainer()->getServer()->getLogger();
$this->consoleHooks();
$this->appHooks();
$this->userManagementHooks($logger);
$this->groupHooks($logger);
$this->authHooks($logger);
$this->sharingHooks();
$this->consoleHooks($logger);
$this->appHooks($logger);
$this->fileHooks();
$this->trashbinHooks();
$this->versionsHooks();
$this->sharingHooks($logger);
$this->securityHooks();
$this->fileHooks($logger);
$this->trashbinHooks($logger);
$this->versionsHooks($logger);
}
protected function userManagementHooks() {
$userActions = new UserManagement($this->logger);
protected function userManagementHooks(ILogger $logger) {
$userActions = new UserManagement($logger);
Util::connectHook('OC_User', 'post_createUser', $userActions, 'create');
Util::connectHook('OC_User', 'post_deleteUser', $userActions, 'delete');
@@ -109,12 +87,10 @@ class Application extends App {
/** @var IUserSession|Session $userSession */
$userSession = $this->getContainer()->getServer()->getUserSession();
$userSession->listen('\OC\User', 'postSetPassword', [$userActions, 'setPassword']);
$userSession->listen('\OC\User', 'assignedUserId', [$userActions, 'assign']);
$userSession->listen('\OC\User', 'postUnassignedUserId', [$userActions, 'unassign']);
}
protected function groupHooks() {
$groupActions = new GroupManagement($this->logger);
protected function groupHooks(ILogger $logger) {
$groupActions = new GroupManagement($logger);
/** @var IGroupManager|Manager $groupManager */
$groupManager = $this->getContainer()->getServer()->getGroupManager();
@@ -124,53 +100,53 @@ class Application extends App {
$groupManager->listen('\OC\Group', 'postCreate', [$groupActions, 'createGroup']);
}
protected function sharingHooks() {
$shareActions = new Sharing($this->logger);
protected function sharingHooks(ILogger $logger) {
$shareActions = new Sharing($logger);
Util::connectHook(Share::class, 'post_shared', $shareActions, 'shared');
Util::connectHook(Share::class, 'post_unshare', $shareActions, 'unshare');
Util::connectHook(Share::class, 'post_update_permissions', $shareActions, 'updatePermissions');
Util::connectHook(Share::class, 'post_update_password', $shareActions, 'updatePassword');
Util::connectHook(Share::class, 'post_set_expiration_date', $shareActions, 'updateExpirationDate');
Util::connectHook(Share::class, 'share_link_access', $shareActions, 'shareAccessed');
Util::connectHook('OCP\Share', 'post_shared', $shareActions, 'shared');
Util::connectHook('OCP\Share', 'post_unshare', $shareActions, 'unshare');
Util::connectHook('OCP\Share', 'post_update_permissions', $shareActions, 'updatePermissions');
Util::connectHook('OCP\Share', 'post_update_password', $shareActions, 'updatePassword');
Util::connectHook('OCP\Share', 'post_set_expiration_date', $shareActions, 'updateExpirationDate');
Util::connectHook('OCP\Share', 'share_link_access', $shareActions, 'shareAccessed');
}
protected function authHooks() {
$authActions = new Auth($this->logger);
protected function authHooks(ILogger $logger) {
$authActions = new Auth($logger);
Util::connectHook('OC_User', 'pre_login', $authActions, 'loginAttempt');
Util::connectHook('OC_User', 'post_login', $authActions, 'loginSuccessful');
Util::connectHook('OC_User', 'logout', $authActions, 'logout');
}
protected function appHooks() {
protected function appHooks(ILogger $logger) {
$eventDispatcher = $this->getContainer()->getServer()->getEventDispatcher();
$eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE, function(ManagerEvent $event) {
$appActions = new AppManagement($this->logger);
$eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE, function(ManagerEvent $event) use ($logger) {
$appActions = new AppManagement($logger);
$appActions->enableApp($event->getAppID());
});
$eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, function(ManagerEvent $event) {
$appActions = new AppManagement($this->logger);
$eventDispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE_FOR_GROUPS, function(ManagerEvent $event) use ($logger) {
$appActions = new AppManagement($logger);
$appActions->enableAppForGroups($event->getAppID(), $event->getGroups());
});
$eventDispatcher->addListener(ManagerEvent::EVENT_APP_DISABLE, function(ManagerEvent $event) {
$appActions = new AppManagement($this->logger);
$eventDispatcher->addListener(ManagerEvent::EVENT_APP_DISABLE, function(ManagerEvent $event) use ($logger) {
$appActions = new AppManagement($logger);
$appActions->disableApp($event->getAppID());
});
}
protected function consoleHooks() {
protected function consoleHooks(ILogger $logger) {
$eventDispatcher = $this->getContainer()->getServer()->getEventDispatcher();
$eventDispatcher->addListener(ConsoleEvent::EVENT_RUN, function(ConsoleEvent $event) {
$appActions = new Console($this->logger);
$eventDispatcher->addListener(ConsoleEvent::EVENT_RUN, function(ConsoleEvent $event) use ($logger) {
$appActions = new Console($logger);
$appActions->runCommand($event->getArguments());
});
}
protected function fileHooks() {
$fileActions = new Files($this->logger);
protected function fileHooks(ILogger $logger) {
$fileActions = new Files($logger);
$eventDispatcher = $this->getContainer()->getServer()->getEventDispatcher();
$eventDispatcher->addListener(
IPreview::EVENT,
@@ -231,27 +207,15 @@ class Application extends App {
);
}
protected function versionsHooks() {
$versionsActions = new Versions($this->logger);
protected function versionsHooks(ILogger $logger) {
$versionsActions = new Versions($logger);
Util::connectHook('\OCP\Versions', 'rollback', $versionsActions, 'rollback');
Util::connectHook('\OCP\Versions', 'delete',$versionsActions, 'delete');
}
protected function trashbinHooks() {
$trashActions = new Trashbin($this->logger);
protected function trashbinHooks(ILogger $logger) {
$trashActions = new Trashbin($logger);
Util::connectHook('\OCP\Trashbin', 'preDelete', $trashActions, 'delete');
Util::connectHook('\OCA\Files_Trashbin\Trashbin', 'post_restore', $trashActions, 'restore');
}
protected function securityHooks() {
$eventDispatcher = $this->getContainer()->getServer()->getEventDispatcher();
$eventDispatcher->addListener(IProvider::EVENT_SUCCESS, function(GenericEvent $event) {
$security = new Security($this->logger);
$security->twofactorSuccess($event->getSubject(), $event->getArguments());
});
$eventDispatcher->addListener(IProvider::EVENT_FAILED, function(GenericEvent $event) {
$security = new Security($this->logger);
$security->twofactorFailed($event->getSubject(), $event->getArguments());
});
}
}
@@ -1,52 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2018 Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\AdminAudit\BackgroundJobs;
use OC\BackgroundJob\TimedJob;
use OCP\Log\RotationTrait;
class Rotate extends TimedJob {
use RotationTrait;
public function __construct() {
$this->setInterval(60*60*3);
}
protected function run($argument) {
$config = \OC::$server->getConfig();
$default = $config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/audit.log';
$this->filePath = $config->getAppValue('admin_audit', 'logfile', $default);
if($this->filePath === '') {
// default log file, nothing to do
return;
}
$this->maxSize = $config->getSystemValue('log_rotate_size', 100 * 1024 * 1024);
if($this->shouldRotateBySize()) {
$this->rotate();
}
}
}
@@ -1,75 +0,0 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2018 Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\AdminAudit\Tests\Actions;
use OCA\AdminAudit\Actions\Security;
use OCP\ILogger;
use OCP\IUser;
use Test\TestCase;
class SecurityTest extends TestCase {
/** @var ILogger|\PHPUnit_Framework_MockObject_MockObject */
private $logger;
/** @var Security */
private $security;
/** @var IUser|\PHPUnit_Framework_MockObject_MockObject */
private $user;
public function setUp() {
parent::setUp();
$this->logger = $this->createMock(ILogger::class);
$this->security = new Security($this->logger);
$this->user = $this->createMock(IUser::class);
$this->user->method('getUID')->willReturn('myuid');
$this->user->method('getDisplayName')->willReturn('mydisplayname');
}
public function testTwofactorFailed() {
$this->logger->expects($this->once())
->method('info')
->with(
$this->equalTo('Failed two factor attempt by user mydisplayname (myuid) with provider myprovider'),
['app' => 'admin_audit']
);
$this->security->twofactorFailed($this->user, ['provider' => 'myprovider']);
}
public function testTwofactorSuccess() {
$this->logger->expects($this->once())
->method('info')
->with(
$this->equalTo('Successful two factor attempt by user mydisplayname (myuid) with provider myprovider'),
['app' => 'admin_audit']
);
$this->security->twofactorSuccess($this->user, ['provider' => 'myprovider']);
}
}
-661
View File
@@ -1,661 +0,0 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.
-2
View File
@@ -1,2 +0,0 @@
# cloud_federation_api
The cloud federation API allows to share information like files, contacts, calendars, incoming calls, etc accross Nextcloud instances
-22
View File
@@ -1,22 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2018 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
$app = new \OCA\CloudFederationAPI\AppInfo\Application();
@@ -1,20 +0,0 @@
<?xml version="1.0"?>
<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
<id>cloud_federation_api</id>
<name>Cloud Federation API</name>
<summary>Enable clouds to communicate with each other and exchange data</summary>
<description>The Cloud Federation API enables various Nextcloud instances to communicate with each other and to exchange data.</description>
<version>0.0.1</version>
<licence>agpl</licence>
<author>Bjoern Schiessle</author>
<namespace>CloudFederationAPI</namespace>
<types>
<filesystem/>
</types>
<category>files</category>
<bugs>https://github.com/nextcloud/cloud_federation/issues</bugs>
<dependencies>
<nextcloud min-version="14" max-version="14"/>
</dependencies>
</info>
@@ -1,37 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2018 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\CloudFederationAPI\AppInfo;
use OCA\CloudFederationAPI\Capabilities;
use OCP\AppFramework\App;
class Application extends App {
public function __construct() {
parent::__construct('cloud_federation_api');
$container = $this->getContainer();
$container->registerCapability(Capabilities::class);
}
}
@@ -1,64 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2017 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\CloudFederationAPI;
use OCP\Capabilities\ICapability;
use OCP\IURLGenerator;
class Capabilities implements ICapability {
/** @var IURLGenerator */
private $urlGenerator;
public function __construct(IURLGenerator $urlGenerator) {
$this->urlGenerator = $urlGenerator;
}
/**
* Function an app uses to return the capabilities
*
* @return array Array containing the apps capabilities
* @since 8.2.0
*/
public function getCapabilities() {
$url = $this->urlGenerator->linkToRouteAbsolute('cloud_federation_api.requesthandlercontroller.addShare');
$capabilities = ['ocm' =>
[
'enabled' => true,
'apiVersion' => '1.0-proposal1',
'endPoint' => substr($url, 0, strrpos($url, '/')),
'shareTypes' => [
[
'name' => 'file',
'protocols' => [
'webdav' => '/public.php/webdav/',
]
],
]
]
];
return $capabilities;
}
}
-60
View File
@@ -1,60 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2018 Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\CloudFederationAPI;
use OCP\Federation\ICloudFederationProviderManager;
use OCP\GlobalScale\IConfig as IGsConfig;
use OCP\IConfig;
/**
* Class config
*
* handles all the config parameters
*
* @package OCA\CloudFederationAPI
*/
class Config {
/** @var ICloudFederationProviderManager */
private $cloudFederationProviderManager;
public function __construct(ICloudFederationProviderManager $cloudFederationProviderManager) {
$this->cloudFederationProviderManager = $cloudFederationProviderManager;
}
/**
* get a list of supported share types
*
* @param string $resourceType
* @return array
*/
public function getSupportedShareTypes($resourceType) {
try {
$provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType);
return $provider->getSupportedShareTypes();
} catch (\Exception $e) {
return [];
}
}
}
@@ -1,300 +0,0 @@
<?php
/**
* @copyright Copyright (c) 2018 Bjoern Schiessle <bjoern@schiessle.org>
*
* @author Bjoern Schiessle <bjoern@schiessle.org>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\CloudFederationAPI\Controller;
use OCA\CloudFederationAPI\Config;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse;
use OCP\Federation\Exceptions\ActionNotSupportedException;
use OCP\Federation\Exceptions\AuthenticationFailedException;
use OCP\Federation\Exceptions\BadRequestException;
use OCP\Federation\Exceptions\ProviderCouldNotAddShareException;
use OCP\Federation\ICloudFederationFactory;
use OCP\Federation\ICloudFederationProviderManager;
use OCP\Federation\Exceptions\ProviderDoesNotExistsException;
use OCP\Federation\ICloudIdManager;
use OCP\IGroupManager;
use OCP\ILogger;
use OCP\IRequest;
use OCP\IURLGenerator;
use OCP\IUserManager;
use OCP\Share\Exceptions\ShareNotFound;
/**
* Class RequestHandlerController
*
* handle API between different Cloud instances
*
* @package OCA\CloudFederationAPI\Controller
*/
class RequestHandlerController extends Controller {
/** @var ILogger */
private $logger;
/** @var IUserManager */
private $userManager;
/** @var IGroupManager */
private $groupManager;
/** @var IURLGenerator */
private $urlGenerator;
/** @var ICloudFederationProviderManager */
private $cloudFederationProviderManager;
/** @var Config */
private $config;
/** @var ICloudFederationFactory */
private $factory;
/** @var ICloudIdManager */
private $cloudIdManager;
public function __construct($appName,
IRequest $request,
ILogger $logger,
IUserManager $userManager,
IGroupManager $groupManager,
IURLGenerator $urlGenerator,
ICloudFederationProviderManager $cloudFederationProviderManager,
Config $config,
ICloudFederationFactory $factory,
ICloudIdManager $cloudIdManager
) {
parent::__construct($appName, $request);
$this->logger = $logger;
$this->userManager = $userManager;
$this->groupManager = $groupManager;
$this->urlGenerator = $urlGenerator;
$this->cloudFederationProviderManager = $cloudFederationProviderManager;
$this->config = $config;
$this->factory = $factory;
$this->cloudIdManager = $cloudIdManager;
}
/**
* add share
*
* @NoCSRFRequired
* @PublicPage
* @BruteForceProtection(action=receiveFederatedShare)
*
* @param string $shareWith
* @param string $name resource name (e.g. document.odt)
* @param string $description share description (optional)
* @param string $providerId resource UID on the provider side
* @param string $owner provider specific UID of the user who owns the resource
* @param string $ownerDisplayName display name of the user who shared the item
* @param string $sharedBy provider specific UID of the user who shared the resource
* @param string $sharedByDisplayName display name of the user who shared the resource
* @param array $protocol (e,.g. ['name' => 'webdav', 'options' => ['username' => 'john', 'permissions' => 31]])
* @param string $shareType ('group' or 'user' share)
* @param $resourceType ('file', 'calendar',...)
* @return Http\DataResponse|JSONResponse
*
* Example: curl -H "Content-Type: application/json" -X POST -d '{"shareWith":"admin1@serve1","name":"welcome server2.txt","description":"desc","providerId":"2","owner":"admin2@http://localhost/server2","ownerDisplayName":"admin2 display","shareType":"user","resourceType":"file","protocol":{"name":"webdav","options":{"sharedSecret":"secret","permissions":"webdav-property"}}}' http://localhost/server/index.php/ocm/shares
*/
public function addShare($shareWith, $name, $description, $providerId, $owner, $ownerDisplayName, $sharedBy, $sharedByDisplayName, $protocol, $shareType, $resourceType) {
// check if all required parameters are set
if ($shareWith === null ||
$name === null ||
$providerId === null ||
$owner === null ||
$resourceType === null ||
$shareType === null ||
!is_array($protocol) ||
!isset($protocol['name']) ||
!isset ($protocol['options']) ||
!is_array($protocol['options']) ||
!isset($protocol['options']['sharedSecret'])
) {
return new JSONResponse(
['message' => 'Missing arguments'],
Http::STATUS_BAD_REQUEST
);
}
$supportedShareTypes = $this->config->getSupportedShareTypes($resourceType);
if (!in_array($shareType, $supportedShareTypes)) {
return new JSONResponse(
['message' => 'Share type "' . $shareType . '" not implemented'],
Http::STATUS_NOT_IMPLEMENTED
);
}
$cloudId = $this->cloudIdManager->resolveCloudId($shareWith);
$shareWith = $cloudId->getUser();
if ($shareType === 'user') {
$shareWith = $this->mapUid($shareWith);
if (!$this->userManager->userExists($shareWith)) {
return new JSONResponse(
['message' => 'User "' . $shareWith . '" does not exists at ' . $this->urlGenerator->getBaseUrl()],
Http::STATUS_BAD_REQUEST
);
}
}
if ($shareType === 'group') {
if(!$this->groupManager->groupExists($shareWith)) {
return new JSONResponse(
['message' => 'Group "' . $shareWith . '" does not exists at ' . $this->urlGenerator->getBaseUrl()],
Http::STATUS_BAD_REQUEST
);
}
}
// if no explicit display name is given, we use the uid as display name
$ownerDisplayName = $ownerDisplayName === null ? $owner : $ownerDisplayName;
$sharedByDisplayName = $sharedByDisplayName === null ? $sharedBy : $sharedByDisplayName;
// sharedBy* parameter is optional, if nothing is set we assume that it is the same user as the owner
if ($sharedBy === null) {
$sharedBy = $owner;
$sharedByDisplayName = $ownerDisplayName;
}
try {
$provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType);
$share = $this->factory->getCloudFederationShare($shareWith, $name, $description, $providerId, $owner, $ownerDisplayName, $sharedBy, $sharedByDisplayName, '', $shareType, $resourceType);
$share->setProtocol($protocol);
$provider->shareReceived($share);
} catch (ProviderDoesNotExistsException $e) {
return new JSONResponse(
['message' => $e->getMessage()],
Http::STATUS_NOT_IMPLEMENTED
);
} catch (ProviderCouldNotAddShareException $e) {
return new JSONResponse(
['message' => $e->getMessage()],
$e->getCode()
);
} catch (\Exception $e) {
return new JSONResponse(
['message' => 'Internal error at ' . $this->urlGenerator->getBaseUrl()],
Http::STATUS_BAD_REQUEST
);
}
$user = $this->userManager->get($shareWith);
$recipientDisplayName = '';
if($user) {
$recipientDisplayName = $user->getDisplayName();
}
return new JSONResponse(
['recipientDisplayName' => $recipientDisplayName],
Http::STATUS_CREATED);
}
/**
* receive notification about existing share
*
* @NoCSRFRequired
* @PublicPage
* @BruteForceProtection(action=receiveFederatedShareNotification)
*
* @param string $notificationType (notification type, e.g. SHARE_ACCEPTED)
* @param string $resourceType (calendar, file, contact,...)
* @param string $providerId id of the share
* @param array $notification the actual payload of the notification
* @return JSONResponse
*/
public function receiveNotification($notificationType, $resourceType, $providerId, array $notification) {
// check if all required parameters are set
if ($notificationType === null ||
$resourceType === null ||
$providerId === null ||
!is_array($notification)
) {
return new JSONResponse(
['message' => 'Missing arguments'],
Http::STATUS_BAD_REQUEST
);
}
try {
$provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType);
$result = $provider->notificationReceived($notificationType, $providerId, $notification);
} catch (ProviderDoesNotExistsException $e) {
return new JSONResponse(
['message' => $e->getMessage()],
Http::STATUS_BAD_REQUEST
);
} catch (ShareNotFound $e) {
return new JSONResponse(
['message' => $e->getMessage()],
Http::STATUS_BAD_REQUEST
);
} catch (ActionNotSupportedException $e) {
return new JSONResponse(
['message' => $e->getMessage()],
Http::STATUS_NOT_IMPLEMENTED
);
} catch (BadRequestException $e) {
return new JSONResponse($e->getReturnMessage(), Http::STATUS_BAD_REQUEST);
} catch (AuthenticationFailedException $e) {
return new JSONResponse(["message" => "RESOURCE_NOT_FOUND"], Http::STATUS_FORBIDDEN);
}
catch (\Exception $e) {
return new JSONResponse(
['message' => 'Internal error at ' . $this->urlGenerator->getBaseUrl()],
Http::STATUS_BAD_REQUEST
);
}
return new JSONResponse($result,Http::STATUS_CREATED);
}
/**
* map login name to internal LDAP UID if a LDAP backend is in use
*
* @param string $uid
* @return string mixed
*/
private function mapUid($uid) {
// FIXME this should be a method in the user management instead
$this->logger->debug('shareWith before, ' . $uid, ['app' => $this->appName]);
\OCP\Util::emitHook(
'\OCA\Files_Sharing\API\Server2Server',
'preLoginNameUsedAsUserName',
array('uid' => &$uid)
);
$this->logger->debug('shareWith after, ' . $uid, ['app' => $this->appName]);
return $uid;
}
}
-2
View File
@@ -1,2 +0,0 @@
# compiled vue templates
js/templates.js
+48 -11
View File
@@ -1,25 +1,62 @@
<?php
/**
* @copyright Copyright (c) 2018, Joas Schilling <coding@schilljs.com>
* @copyright Copyright (c) 2016, ownCloud, Inc.
*
* @author Arthur Schiwon <blizzz@arthur-schiwon.de>
* @author Joas Schilling <coding@schilljs.com>
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Vincent Petry <pvince81@owncloud.com>
*
* @license GNU AGPL version 3 or any later version
* @license AGPL-3.0
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
$application = new \OCA\Comments\AppInfo\Application();
$application->register();
$eventDispatcher = \OC::$server->getEventDispatcher();
$eventDispatcher->addListener(
'OCA\Files::loadAdditionalScripts',
function() {
\OCP\Util::addScript('oc-backbone-webdav');
\OCP\Util::addScript('comments', 'merged');
\OCP\Util::addStyle('comments', 'autocomplete');
\OCP\Util::addStyle('comments', 'comments');
}
);
$eventDispatcher->addListener(\OCP\Comments\CommentsEntityEvent::EVENT_ENTITY, function(\OCP\Comments\CommentsEntityEvent $event) {
$event->addEntityCollection('files', function($name) {
$nodes = \OC::$server->getUserFolder()->getById(intval($name));
return !empty($nodes);
});
});
$notificationManager = \OC::$server->getNotificationManager();
$notificationManager->registerNotifier(
function() {
$application = new \OCP\AppFramework\App('comments');
return $application->getContainer()->query(\OCA\Comments\Notification\Notifier::class);
},
function () {
$l = \OC::$server->getL10N('comments');
return ['id' => 'comments', 'name' => $l->t('Comments')];
}
);
$commentsManager = \OC::$server->getCommentsManager();
$commentsManager->registerEventHandler(function () {
$application = new \OCP\AppFramework\App('comments');
/** @var \OCA\Comments\EventHandler $handler */
$handler = $application->getContainer()->query(\OCA\Comments\EventHandler::class);
return $handler;
});
+6 -11
View File
@@ -1,24 +1,19 @@
<?xml version="1.0"?>
<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
<info>
<id>comments</id>
<name>Comments</name>
<summary>Files app plugin to add comments to files</summary>
<description>Files app plugin to add comments to files</description>
<version>1.4.0</version>
<licence>agpl</licence>
<licence>AGPL</licence>
<author>Arthur Schiwon</author>
<author>Vincent Petry</author>
<default_enable/>
<version>1.3.0</version>
<dependencies>
<nextcloud min-version="13" max-version="13" />
</dependencies>
<types>
<logging/>
</types>
<category>office</category>
<category>social</category>
<bugs>https://github.com/nextcloud/server/issues</bugs>
<dependencies>
<nextcloud min-version="14" max-version="14" />
</dependencies>
<activity>
<settings>
@@ -43,7 +43,8 @@ namespace Composer\Autoload;
class ClassLoader
{
// PSR-4
private $prefixLengthsPsr4 = array();
private $firstCharsPsr4 = array();
private $prefixLengthsPsr4 = array(); // For BC with legacy static maps
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
@@ -170,11 +171,10 @@ class ClassLoader
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
if ('\\' !== substr($prefix, -1)) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->firstCharsPsr4[$prefix[0]] = true;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
@@ -221,11 +221,10 @@ class ClassLoader
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
if ('\\' !== substr($prefix, -1)) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->firstCharsPsr4[$prefix[0]] = true;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
@@ -279,7 +278,7 @@ class ClassLoader
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
}
/**
@@ -373,11 +372,11 @@ class ClassLoader
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
if (isset($this->firstCharsPsr4[$first]) || isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
$search = $subPath.'\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
@@ -17,6 +17,4 @@ return array(
'OCA\\Comments\\JSSettingsHelper' => $baseDir . '/../lib/JSSettingsHelper.php',
'OCA\\Comments\\Notification\\Listener' => $baseDir . '/../lib/Notification/Listener.php',
'OCA\\Comments\\Notification\\Notifier' => $baseDir . '/../lib/Notification/Notifier.php',
'OCA\\Comments\\Search\\Provider' => $baseDir . '/../lib/Search/Provider.php',
'OCA\\Comments\\Search\\Result' => $baseDir . '/../lib/Search/Result.php',
);
@@ -6,11 +6,8 @@ namespace Composer\Autoload;
class ComposerStaticInitComments
{
public static $prefixLengthsPsr4 = array (
'O' =>
array (
'OCA\\Comments\\' => 13,
),
public static $firstCharsPsr4 = array (
'O' => true,
);
public static $prefixDirsPsr4 = array (
@@ -32,14 +29,12 @@ class ComposerStaticInitComments
'OCA\\Comments\\JSSettingsHelper' => __DIR__ . '/..' . '/../lib/JSSettingsHelper.php',
'OCA\\Comments\\Notification\\Listener' => __DIR__ . '/..' . '/../lib/Notification/Listener.php',
'OCA\\Comments\\Notification\\Notifier' => __DIR__ . '/..' . '/../lib/Notification/Notifier.php',
'OCA\\Comments\\Search\\Provider' => __DIR__ . '/..' . '/../lib/Search/Provider.php',
'OCA\\Comments\\Search\\Result' => __DIR__ . '/..' . '/../lib/Search/Result.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInitComments::$prefixLengthsPsr4;
$loader->firstCharsPsr4 = ComposerStaticInitComments::$firstCharsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInitComments::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInitComments::$classMap;
+15 -15
View File
@@ -9,11 +9,11 @@
left: 0;
display: none;
margin-top: 18px;
background: var(--color-main-background);
color: var(--color-main-text);
border: 1px solid var(--color-border);
border-radius: var(--border-radius);
box-shadow: 0 0 5px var(--color-box-shadow);
background: $color-main-background;
color: $color-main-text;
border: 1px solid $color-border;
border-radius: $border-radius;
box-shadow: 0 0 5px $color-box-shadow;
min-width: 120px;
z-index: 11110 !important;
}
@@ -22,14 +22,14 @@
padding: 5px;
margin: 5px;
cursor: pointer;
border-bottom: solid 1px var(--color-border);
color: var(--color-main-text);
border-bottom: solid 1px $color-border;
color: $color-main-text;
font-size: 11px;
font-weight: bold;
}
.atwho-view .atwho-header .small {
color: var(--color-main-text);
color: $color-main-text;
float: right;
padding-top: 2px;
margin-right: -5px;
@@ -42,18 +42,18 @@
}
.atwho-view .cur {
background: var(--color-primary);
color: var(--color-primary-text);
background: $color-primary;
color: $color-primary-text;
}
.atwho-view .cur small {
color: var(--color-primary-text);
color: $color-primary-text;
}
.atwho-view strong {
color: var(--color-main-text);
color: $color-main-text;
font-weight: normal;
}
.atwho-view .cur strong {
color: var(--color-primary-text);
color: $color-primary-text;
font-weight: normal;
}
.atwho-view ul {
@@ -67,11 +67,11 @@
.atwho-view ul li {
display: block;
padding: 5px 10px;
border-bottom: 1px solid var(--color-border);
border-bottom: 1px solid $color-border;
cursor: pointer;
}
.atwho-view small {
font-size: smaller;
color: var(--color-main-text);
color: $color-main-text;
font-weight: normal;
}
@@ -13,46 +13,55 @@
}
#commentsTabView .newCommentForm {
margin-left: 36px;
position: relative;
margin-bottom: 20px;
}
#commentsTabView .newCommentForm .message {
width: 100%;
padding: 10px;
min-height: 44px;
margin: 0;
/* Prevent the text from overlapping with the submit button. */
width: calc(100% - 81px); /* 36 (left margin) + 30 (right padding) + 15 (right padding of surrounding box) */
margin-left: 36px;
padding-right: 30px;
display: block;
}
#commentsTabView .newCommentForm {
.submit,
.submitLoading {
width: 44px;
height: 44px;
margin: 0;
padding: 13px;
background-color: transparent;
border: none;
opacity: .3;
position: absolute;
bottom: 0;
right: 0;
}
#commentsTabView .newCommentForm .submit {
position: absolute;
bottom: 0px;
right: 8px;
width: 30px;
margin: 0;
padding: 7px 9px;
background-color: transparent;
border: none;
opacity: .3;
}
#commentsTabView .deleteLoading {
padding: 14px;
vertical-align: middle;
}
#commentsTabView .newCommentForm .submit:not(:disabled):hover,
#commentsTabView .newCommentForm .submit:not(:disabled):focus {
opacity: 1;
}
#commentsTabView .newCommentForm .submitLoading {
background-position: left;
/* Match rules for '#commentsTabView .newCommentForm .submit' to place the
loading icon at the same position as the confirm icon */
position: absolute;
bottom: 0px;
right: 8px;
width: 30px;
margin: 0;
padding: 7px 9px;
/* Match rules for 'input[type="submit"]' to place the loading icon at the
same position as the confirm icon */
min-height: 34px;
box-sizing: border-box;
}
#commentsTabView .newCommentForm .cancel {
margin-right: 6px;
}
#commentsTabView .newCommentForm div.message {
resize: none;
}
@@ -64,12 +73,9 @@
#commentsTabView .comment {
position: relative;
/** padding bottom is little more so that the top and bottom gap look uniform **/
padding: 10px 0px 15px;
}
#commentsTabView .comments .comment {
border-top: 1px solid var(--color-border);
margin-bottom: 30px;
word-wrap: break-word;
overflow-wrap: break-word;
}
#commentsTabView .comment .avatar,
@@ -117,23 +123,20 @@
background: -o-linear-gradient(rgba(255,255,255,0), rgba(255,255,255,1));
background: -ms-linear-gradient(rgba(255,255,255,0), rgba(255,255,255,1));
background: linear-gradient(rgba(255,255,255,0), rgba(255,255,255,1));
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#00FFFFFF', endColorstr='#FFFFFFFF');
background-repeat: no-repeat;
}
#commentsTabView .hidden {
#commentsTabView .authorRow>div:not(.contactsmenu-popover) {
display: inline-block;
vertical-align: middle;
}
#commentsTabView .authorRow>div.hidden {
display: none !important;
}
/** set min-height as 44px to ensure that it fits the button sizes. **/
#commentsTabView .comment .authorRow {
min-height: 44px;
}
#commentsTabView .comment .authorRow .tooltip {
/** because of the padding on the element, the tooltip appear too far up,
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;
@@ -144,105 +147,64 @@
#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 img {
.atwho-view-ul .avatar-name-wrapper .avatar {
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;
}
height: 16px;
width: 16px;
vertical-align: middle;
padding: 1px;
margin-top: -3px;
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);
}
#commentsTabView .comments li .message .atwho-inserted {
margin-left: 5px;
}
.atwho-view-ul * .avatar-name-wrapper {
white-space: nowrap;
}
#commentsTabView .comment .author,
#commentsTabView .comment .date {
opacity: .5;
}
#commentsTabView .comment .author {
max-width: 210px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
#commentsTabView .comment .date {
margin-left: auto;
/** this is to fix the tooltip being too close due to the margin-top applied
to bring the tooltip closer for the action icons **/
padding: 10px 0px;
}
#commentsTabView .comments > li:not(.newCommentRow) .message {
#commentsTabView .comments li .message {
padding-left: 40px;
word-wrap: break-word;
overflow-wrap: break-word;
display: inline-flex;
flex-wrap: wrap;
align-items: center;
}
#commentsTabView .comment .action {
opacity: 0.3;
padding: 14px;
display: block;
opacity: 0;
padding: 5px;
}
#commentsTabView .comment .action:hover,
#commentsTabView .comment .action:focus {
#commentsTabView .comment:hover .action {
opacity: 0.3;
}
#commentsTabView .comment .action:hover {
opacity: 1;
}
#commentsTabView .newCommentRow .action-container {
margin-left: auto;
#commentsTabView .comment .action.delete,
#commentsTabView .comment .deleteLoading {
position: absolute;
right: 0;
}
#commentsTabView .comment.disabled .message {
#commentsTabView .comment.disabled {
opacity: 0.3;
}
#commentsTabView .comment.disabled .action {
display: none;
visibility: hidden;
}
#commentsTabView .message.error {
@@ -254,8 +216,3 @@
.app-files .action-comment {
padding: 16px 14px;
}
#commentsTabView .comment .message .contactsmenu-popover {
left: -6px;
top: 24px;
}
-124
View File
@@ -1,124 +0,0 @@
/*
* Copyright (c) 2018
*
* This file is licensed under the Affero General Public License version 3
* or later.
*
* See the COPYING-README file.
*
*/
/* global Handlebars */
(function() {
var TEMPLATE_MENU =
'<ul>' +
'{{#each items}}' +
'<li>' +
'<a href="#" class="menuitem action {{name}} permanent" data-action="{{name}}">' +
'{{#if iconClass}}' +
'<span class="icon {{iconClass}}"></span>' +
'{{else}}' +
'<span class="no-icon"></span>' +
'{{/if}}' +
'<span>{{displayName}}</span>' +
'</li>' +
'{{/each}}' +
'</ul>';
/**
* Construct a new CommentsModifyMenuinstance
* @constructs CommentsModifyMenu
* @memberof OC.Comments
*/
var CommentsModifyMenu = OC.Backbone.View.extend({
tagName: 'div',
className: 'commentsModifyMenu popovermenu bubble menu',
_scopes: [
{
name: 'edit',
displayName: t('comments', 'Edit comment'),
iconClass: 'icon-rename'
},
{
name: 'delete',
displayName: t('comments', 'Delete comment'),
iconClass: 'icon-delete'
}
],
initialize: function() {
},
events: {
'click a.action': '_onClickAction'
},
template: Handlebars.compile(TEMPLATE_MENU),
/**
* Event handler whenever an action has been clicked within the menu
*
* @param {Object} event event object
*/
_onClickAction: function(event) {
var $target = $(event.currentTarget);
if (!$target.hasClass('menuitem')) {
$target = $target.closest('.menuitem');
}
OC.hideMenus();
this.trigger('select:menu-item-clicked', event, $target.data('action'));
},
/**
* Renders the menu with the currently set items
*/
render: function() {
this.$el.html(this.template({
items: this._scopes
}));
},
/**
* Displays the menu
*/
show: function(context) {
this._context = context;
for(var i in this._scopes) {
this._scopes[i].active = false;
}
var $el = $(context.target);
var offsetIcon = $el.offset();
var offsetContainer = $el.closest('.authorRow').offset();
// adding some extra top offset to push the menu below the button.
var position = {
top: offsetIcon.top - offsetContainer.top + 48,
left: '',
right: ''
};
position.left = offsetIcon.left - offsetContainer.left;
if (position.left > 200) {
// we need to position the menu to the right.
position.left = '';
position.right = this.$el.closest('.comment').find('.date').width();
this.$el.removeClass('menu-left').addClass('menu-right');
} else {
this.$el.removeClass('menu-right').addClass('menu-left');
}
this.$el.css(position);
this.render();
this.$el.removeClass('hidden');
OC.showMenu(null, this.$el);
}
});
OCA.Comments = OCA.Comments || {};
OCA.Comments.CommentsModifyMenu = CommentsModifyMenu;
})(OC, OCA);
+65 -104
View File
@@ -21,22 +21,24 @@
'<div class="loading hidden" style="height: 50px"></div>';
var EDIT_COMMENT_TEMPLATE =
'<{{tag}} class="newCommentRow comment" data-id="{{id}}">' +
'<div class="newCommentRow comment" data-id="{{id}}">' +
' <div class="authorRow">' +
' <div class="avatar currentUser" data-username="{{actorId}}"></div>' +
' <div class="author currentUser">{{actorDisplayName}}</div>' +
'{{#if isEditMode}}' +
' <div class="action-container">' +
' <a href="#" class="action cancel icon icon-close has-tooltip" title="{{cancelText}}"></a>' +
' </div>' +
' <a href="#" class="action delete icon icon-delete has-tooltip" title="{{deleteTooltip}}"></a>' +
' <div class="deleteLoading icon-loading-small hidden"></div>'+
'{{/if}}' +
' </div>' +
' <form class="newCommentForm">' +
' <div contentEditable="true" class="message" data-placeholder="{{newMessagePlaceholder}}">{{message}}</div>' +
' <input class="submit icon-confirm has-tooltip" type="submit" value="" title="{{submitText}}"/>' +
' <input class="submit icon-confirm" type="submit" value="" />' +
'{{#if isEditMode}}' +
' <input class="cancel pull-right" type="button" value="{{cancelText}}" />' +
'{{/if}}' +
' <div class="submitLoading icon-loading-small hidden"></div>'+
' </form>' +
'</{{tag}}>';
'</div>';
var COMMENT_TEMPLATE =
'<li class="comment{{#if isUnread}} unread{{/if}}{{#if isLong}} collapsed{{/if}}" data-id="{{id}}">' +
@@ -44,8 +46,7 @@
' <div class="avatar{{#if isUserAuthor}} currentUser{{/if}}" {{#if actorId}}data-username="{{actorId}}"{{/if}}> </div>' +
' <div class="author{{#if isUserAuthor}} currentUser{{/if}}">{{actorDisplayName}}</div>' +
'{{#if isUserAuthor}}' +
' <a href="#" class="action more icon icon-more has-tooltip"></a>' +
' <div class="deleteLoading icon-loading-small hidden"></div>' +
' <a href="#" class="action edit icon icon-rename has-tooltip" title="{{editTooltip}}"></a>' +
'{{/if}}' +
' <div class="date has-tooltip live-relative-timestamp" data-timestamp="{{timestamp}}" title="{{altDate}}">{{date}}</div>' +
' </div>' +
@@ -63,11 +64,12 @@
id: 'commentsTabView',
className: 'tab commentsTabView',
_autoCompleteData: undefined,
_commentsModifyMenu: undefined,
events: {
'submit .newCommentForm': '_onSubmitComment',
'click .showMore': '_onClickShowMore',
'click .action.edit': '_onClickEditComment',
'click .action.delete': '_onClickDeleteComment',
'click .cancel': '_onClickCloseComment',
'click .comment': '_onClickComment',
'keyup div.message': '_onTextChange',
@@ -112,9 +114,9 @@
actorId: currentUser.uid,
actorDisplayName: currentUser.displayName,
newMessagePlaceholder: t('comments', 'New comment …'),
deleteTooltip: t('comments', 'Delete comment'),
submitText: t('comments', 'Post'),
cancelText: t('comments', 'Cancel'),
tag: 'li'
cancelText: t('comments', 'Cancel')
}, params));
},
@@ -164,7 +166,7 @@
emptyResultLabel: t('comments', 'No comments yet, start the conversation!'),
moreLabel: t('comments', 'More comments …')
}));
this.$el.find('.comments').before(this.editCommentTemplate({ tag: 'div'}));
this.$el.find('.comments').before(this.editCommentTemplate({}));
this.$el.find('.has-tooltip').tooltip();
this.$container = this.$el.find('ul.comments');
this.$el.find('.avatar').avatar(OC.getCurrentUser().uid, 32);
@@ -172,7 +174,6 @@
this.$el.find('.message').on('keydown input change', this._onTypeComment);
autosize(this.$el.find('.newCommentRow .message'))
this.$el.find('.newCommentForm .message').focus();
},
_initAutoComplete: function($target) {
@@ -195,28 +196,22 @@
},
sorter: function (q, items) { return items; }
},
displayTpl: function (item) {
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">' +
'<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>';
},
displayTpl: '<li>'
+ '<span class="avatar-name-wrapper">'
+ '<div class="avatar" '
+ 'data-username="${id}"' // for avatars
+ ' data-user="${id}"' // for contactsmenu
+ ' data-user-display-name="${label}"></div>'
+ ' <strong>${label}</strong>'
+ '</span></li>',
insertTpl: ''
+ '<span class="avatar-name-wrapper">'
+ '<div class="avatar" '
+ 'data-username="${id}"' // for avatars
+ ' data-user="${id}"' // for contactsmenu
+ ' data-user-display-name="${label}"></div>'
+ ' <strong>${label}</strong>'
+ '</span>',
searchKey: "label"
});
$target.on('inserted.atwho', function (je, $el) {
@@ -226,7 +221,7 @@
// passing the whole comments form would re-apply and request
// avatars from the server
$(je.target).find(
'span[data-username="' + $el.find('[data-username]').data('username') + '"]'
'div[data-username="' + $el.find('[data-username]').data('username') + '"]'
).parent(),
editionMode
);
@@ -245,22 +240,19 @@
if(!_.isUndefined(this._autoCompleteRequestCall)) {
this._autoCompleteRequestCall.abort();
}
this._autoCompleteRequestCall = $.ajax({
url: OC.linkToOCS('core', 2) + 'autocomplete/get',
data: {
this._autoCompleteRequestCall = $.get(
OC.generateUrl('/autocomplete/get'),
{
search: query,
itemType: 'files',
itemId: s.model.get('id'),
sorter: 'commenters|share-recipients',
limit: OC.appConfig.comments.maxAutoCompleteResults
},
beforeSend: function (request) {
request.setRequestHeader('Accept', 'application/json');
},
success: function (result) {
callback(result.ocs.data);
function (data) {
callback(data);
}
});
);
}, 400);
},
@@ -310,8 +302,6 @@
}
);
}
this.$el.find('.newCommentForm .message').focus();
},
/**
@@ -392,15 +382,7 @@
_postRenderItem: function($el, editionMode) {
$el.find('.has-tooltip').tooltip();
var inlineAvatars = $el.find('.message .avatar');
if ($($el.context).hasClass('message')) {
inlineAvatars = $el.find('.avatar');
}
inlineAvatars.each(function () {
var $this = $(this);
$this.avatar($this.attr('data-username'), 16);
});
$el.find('.authorRow .avatar').each(function () {
$el.find('.avatar').each(function() {
var $this = $(this);
$this.avatar($this.attr('data-username'), 32);
});
@@ -416,24 +398,6 @@
// it is the case when writing a comment and mentioning a person
$message = $el;
}
if (!editionMode) {
var self = this;
// add the dropdown menu to display the edit and delete option
var modifyCommentMenu = new OCA.Comments.CommentsModifyMenu();
$el.find('.authorRow').append(modifyCommentMenu.$el);
$el.find('.more').on('click', _.bind(modifyCommentMenu.show, modifyCommentMenu));
self.listenTo(modifyCommentMenu, 'select:menu-item-clicked', function(ev, action) {
if (action === 'edit') {
self._onClickEditComment(ev);
} else if (action === 'delete') {
self._onClickDeleteComment(ev);
}
});
}
this._postRenderMessage($message, editionMode);
},
@@ -442,13 +406,14 @@
return;
}
$el.find('.avatar-name-wrapper').each(function() {
var $this = $(this);
var $avatar = $this.find('.avatar');
$el.find('.avatar').each(function() {
var avatar = $(this);
var strong = $(this).next();
var appendTo = $(this).parent();
var user = $avatar.data('user');
if (user !== OC.getCurrentUser().uid) {
$this.contactsMenu(user, 0, $this);
var username = $(this).data('username');
if (username !== oc_current_user) {
$.merge(avatar, strong).contactsMenu(avatar.data('user'), 0, appendTo);
}
});
},
@@ -487,22 +452,20 @@
},
_composeHTMLMention: function(uid, displayName) {
var avatar = '' +
'<span class="avatar" ' +
'data-username="' + _.escape(uid) + '" ' +
'data-user="' + _.escape(uid) + '" ' +
'data-user-display-name="' + _.escape(displayName) + '">' +
'</span>';
var avatar = '<div class="avatar" '
+ 'data-username="' + _.escape(uid) + '"'
+ ' data-user="' + _.escape(uid) + '"'
+ ' data-user-display-name="'
+ _.escape(displayName) + '"></div>';
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() {
@@ -601,13 +564,15 @@
var $comment = $(ev.target).closest('.comment');
var commentId = $comment.data('id');
var $loading = $comment.find('.deleteLoading');
var $moreIcon = $comment.find('.more');
var $commentField = $comment.find('.message');
var $submit = $comment.find('.submit');
var $cancel = $comment.find('.cancel');
$commentField.prop('contenteditable', false);
$submit.prop('disabled', true);
$cancel.prop('disabled', true);
$comment.addClass('disabled');
$loading.removeClass('hidden');
$moreIcon.addClass('hidden');
$comment.data('commentEl', $comment);
this.collection.get(commentId).destroy({
success: function() {
@@ -616,8 +581,10 @@
},
error: function() {
$loading.addClass('hidden');
$moreIcon.removeClass('hidden');
$comment.removeClass('disabled');
$commentField.prop('contenteditable', true);
$submit.prop('disabled', false);
$cancel.prop('disabled', false);
OC.Notification.showTemporary(t('comments', 'Error occurred while retrieving comment with ID {id}', {id: commentId}));
}
@@ -698,12 +665,6 @@
}, {
success: function(model) {
self._onSubmitSuccess(model, $form);
if(model.get('message').trim() === model.previous('message').trim()) {
// model change event doesn't trigger, manually remove the row.
var $row = $form.closest('.comment');
$row.data('commentEl').removeClass('hidden');
$row.remove();
}
},
error: function() {
self._onSubmitError($form, commentId);
-2
View File
@@ -4,10 +4,8 @@
"commentcollection.js",
"commentsummarymodel.js",
"commentstabview.js",
"commentsmodifymenu.js",
"filesplugin.js",
"activitytabviewplugin.js",
"search.js",
"vendor/Caret.js/dist/jquery.caret.min.js",
"vendor/At.js/dist/js/jquery.atwho.min.js"
]
-136
View File
@@ -1,136 +0,0 @@
/*
* Copyright (c) 2014
*
* This file is licensed under the Affero General Public License version 3
* or later.
*
* See the COPYING-README file.
*
*/
(function(OC, OCA, $) {
"use strict";
/**
* Construct a new FileActions instance
* @constructs Files
*/
var Comment = function() {
this.initialize();
};
Comment.prototype = {
fileList: null,
/**
* Initialize the file search
*/
initialize: function() {
var self = this;
this.fileAppLoaded = function() {
return !!OCA.Files && !!OCA.Files.App;
};
function inFileList($row, result) {
return false;
if (! self.fileAppLoaded()) {
return false;
}
var dir = self.fileList.getCurrentDirectory().replace(/\/+$/,'');
var resultDir = OC.dirname(result.path);
return dir === resultDir && self.fileList.inList(result.name);
}
function hideNoFilterResults() {
var $nofilterresults = $('.nofilterresults');
if ( ! $nofilterresults.hasClass('hidden') ) {
$nofilterresults.addClass('hidden');
}
}
/**
*
* @param {jQuery} $row
* @param {Object} result
* @param {int} result.id
* @param {string} result.comment
* @param {string} result.authorId
* @param {string} result.authorName
* @param {string} result.link
* @param {string} result.fileName
* @param {string} result.path
* @returns {*}
*/
this.renderCommentResult = function($row, result) {
if (inFileList($row, result)) {
return null;
}
hideNoFilterResults();
/*render preview icon, show path beneath filename,
show size and last modified date on the right */
this.updateLegacyMimetype(result);
var $pathDiv = $('<div>').addClass('path').text(result.path);
var $avatar = $('<div>');
$avatar.addClass('avatar')
.css('display', 'inline-block')
.css('vertical-align', 'middle')
.css('margin', '0 5px 2px 3px');
if (result.authorName) {
$avatar.avatar(result.authorId, 21, undefined, false, undefined, result.authorName);
} else {
$avatar.avatar(result.authorId, 21);
}
$row.find('td.info div.name').after($pathDiv).text(result.comment).prepend($('<span>').addClass('path').css('margin-right', '5px').text(result.authorName)).prepend($avatar);
$row.find('td.result a').attr('href', result.link);
$row.find('td.icon')
.css('background-image', 'url(' + OC.imagePath('core', 'actions/comment') + ')')
.css('opacity', '.4');
var dir = OC.dirname(result.path);
// "result.path" does not include a leading "/", so "OC.dirname"
// returns the path itself for files or folders in the root.
if (dir === result.path) {
dir = '/';
}
$row.find('td.info a').attr('href',
OC.generateUrl('/apps/files/?dir={dir}&scrollto={scrollto}', {dir: dir, scrollto: result.fileName})
);
return $row;
};
this.handleCommentClick = function($row, result, event) {
if (self.fileAppLoaded() && self.fileList.id === 'files') {
self.fileList.changeDirectory(OC.dirname(result.path));
self.fileList.scrollTo(result.name);
return false;
} else {
return true;
}
};
this.updateLegacyMimetype = function (result) {
// backward compatibility:
if (!result.mime && result.mime_type) {
result.mime = result.mime_type;
}
};
this.setFileList = function (fileList) {
this.fileList = fileList;
};
OC.Plugins.register('OCA.Search.Core', this);
},
attach: function(search) {
search.setRenderer('comment', this.renderCommentResult.bind(this));
search.setHandler('comment', this.handleCommentClick.bind(this));
}
};
OCA.Search.comment = new Comment();
})(OC, OCA, $);
+18 -19
View File
@@ -2,6 +2,20 @@ OC.L10N.register(
"comments",
{
"Comments" : "Kommentare",
"New comment …" : "Nuwe kommentaar…",
"Delete comment" : "Skrap kommentaar",
"Post" : "Plaas",
"Cancel" : "Kanselleer",
"Edit comment" : "Wysig kommentaar",
"[Deleted user]" : "[Geskrapte gebruiker]",
"No comments yet, start the conversation!" : "Nog geen kommentaar, begin die gesprek!",
"More comments …" : "Nog kommentare …",
"Save" : "Bewaar",
"Allowed characters {count} of {max}" : "Toegelate karakters {telling} van {maks}",
"Error occurred while updating comment with id {id}" : "n Fout het voorgekom toe kommentaar met id {id} bygewerk is",
"Error occurred while posting comment" : "n Fout het voorgekom toe kommentaar geplaas is",
"_%n unread comment_::_%n unread comments_" : ["%n ongeleesde kommentaar","%n ongeleeste kommentare"],
"Comment" : "Kommentaar",
"You commented" : "U het kommentaar gelewer",
"%1$s commented" : "%1$s het kommentaar gelewer",
"{author} commented" : "{outeur} het kommentaar gelewer",
@@ -10,25 +24,10 @@ OC.L10N.register(
"%1$s commented on %2$s" : "%1$s het op %2$s kommentaar gelewer",
"{author} commented on {file}" : "{outeur} het op {lêer} kommentaar gelewer",
"<strong>Comments</strong> for files" : "<strong>Kommentare</strong> vir lêers",
"You were mentioned on “{file}”, in a comment by a user that has since been deleted" : "Jy is genoem op “{lêer}”, in die kommentaar van 'n gebruiker wat intussen geskrap is.",
"%1$s mentioned you in a comment on “%2$s”" : "%1$s het u in n kommentaar op “%2$s” genoem",
"{user} mentioned you in a comment on “{file}”" : "{gebruiker} het u in n kommentaar oor “{lêer}” genoem",
"Files app plugin to add comments to files" : "Lêertoepinprop om kommentaar op lêers te lewer",
"Edit comment" : "Wysig kommentaar",
"Delete comment" : "Skrap kommentaar",
"New comment …" : "Nuwe kommentaar…",
"Post" : "Plaas",
"Cancel" : "Kanselleer",
"[Deleted user]" : "[Geskrapte gebruiker]",
"No comments yet, start the conversation!" : "Nog geen kommentaar, begin die gesprek!",
"More comments …" : "Nog kommentare …",
"Save" : "Bewaar",
"Allowed characters {count} of {max}" : "Toegelate karakters {telling} van {maks}",
"Error occurred while retrieving comment with ID {id}" : "n Fout het voorgekom toe kommentaar met ID {id} opgehaal is",
"Error occurred while updating comment with id {id}" : "n Fout het voorgekom toe kommentaar met ID {id} bygewerk is",
"Error occurred while posting comment" : "n Fout het voorgekom toe kommentaar geplaas is",
"_%n unread comment_::_%n unread comments_" : ["%n ongelese kommentaar","%n ongelese kommentare"],
"Comment" : "Kommentaar",
"You were mentioned on “%s”, in a comment by a user that has since been deleted" : "Jy was genoem op \"%s\", in die kommentaar van 'n gebruiker wat intussen geskrap is.",
"%1$s mentioned you in a comment on “%2$s”" : "%1$s het u in n kommentaar op “%2$s” genoem"
"Unknown user" : "Onbekende gebruiker",
"A (now) deleted user mentioned you in a comment on “%s”" : "n (Nou) geskrapte gebruiker het u in n kommentaar op “%s” genoem",
"A (now) deleted user mentioned you in a comment on “{file}”" : "n (Nou) geskrapte gebruiker het u in n kommentaar op “{lêer}” genoem"
},
"nplurals=2; plural=(n != 1);");
+18 -19
View File
@@ -1,5 +1,19 @@
{ "translations": {
"Comments" : "Kommentare",
"New comment …" : "Nuwe kommentaar…",
"Delete comment" : "Skrap kommentaar",
"Post" : "Plaas",
"Cancel" : "Kanselleer",
"Edit comment" : "Wysig kommentaar",
"[Deleted user]" : "[Geskrapte gebruiker]",
"No comments yet, start the conversation!" : "Nog geen kommentaar, begin die gesprek!",
"More comments …" : "Nog kommentare …",
"Save" : "Bewaar",
"Allowed characters {count} of {max}" : "Toegelate karakters {telling} van {maks}",
"Error occurred while updating comment with id {id}" : "n Fout het voorgekom toe kommentaar met id {id} bygewerk is",
"Error occurred while posting comment" : "n Fout het voorgekom toe kommentaar geplaas is",
"_%n unread comment_::_%n unread comments_" : ["%n ongeleesde kommentaar","%n ongeleeste kommentare"],
"Comment" : "Kommentaar",
"You commented" : "U het kommentaar gelewer",
"%1$s commented" : "%1$s het kommentaar gelewer",
"{author} commented" : "{outeur} het kommentaar gelewer",
@@ -8,25 +22,10 @@
"%1$s commented on %2$s" : "%1$s het op %2$s kommentaar gelewer",
"{author} commented on {file}" : "{outeur} het op {lêer} kommentaar gelewer",
"<strong>Comments</strong> for files" : "<strong>Kommentare</strong> vir lêers",
"You were mentioned on “{file}”, in a comment by a user that has since been deleted" : "Jy is genoem op “{lêer}”, in die kommentaar van 'n gebruiker wat intussen geskrap is.",
"%1$s mentioned you in a comment on “%2$s”" : "%1$s het u in n kommentaar op “%2$s” genoem",
"{user} mentioned you in a comment on “{file}”" : "{gebruiker} het u in n kommentaar oor “{lêer}” genoem",
"Files app plugin to add comments to files" : "Lêertoepinprop om kommentaar op lêers te lewer",
"Edit comment" : "Wysig kommentaar",
"Delete comment" : "Skrap kommentaar",
"New comment …" : "Nuwe kommentaar…",
"Post" : "Plaas",
"Cancel" : "Kanselleer",
"[Deleted user]" : "[Geskrapte gebruiker]",
"No comments yet, start the conversation!" : "Nog geen kommentaar, begin die gesprek!",
"More comments …" : "Nog kommentare …",
"Save" : "Bewaar",
"Allowed characters {count} of {max}" : "Toegelate karakters {telling} van {maks}",
"Error occurred while retrieving comment with ID {id}" : "n Fout het voorgekom toe kommentaar met ID {id} opgehaal is",
"Error occurred while updating comment with id {id}" : "n Fout het voorgekom toe kommentaar met ID {id} bygewerk is",
"Error occurred while posting comment" : "n Fout het voorgekom toe kommentaar geplaas is",
"_%n unread comment_::_%n unread comments_" : ["%n ongelese kommentaar","%n ongelese kommentare"],
"Comment" : "Kommentaar",
"You were mentioned on “%s”, in a comment by a user that has since been deleted" : "Jy was genoem op \"%s\", in die kommentaar van 'n gebruiker wat intussen geskrap is.",
"%1$s mentioned you in a comment on “%2$s”" : "%1$s het u in n kommentaar op “%2$s” genoem"
"Unknown user" : "Onbekende gebruiker",
"A (now) deleted user mentioned you in a comment on “%s”" : "n (Nou) geskrapte gebruiker het u in n kommentaar op “%s” genoem",
"A (now) deleted user mentioned you in a comment on “{file}”" : "n (Nou) geskrapte gebruiker het u in n kommentaar op “{lêer}” genoem"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}
+10 -11
View File
@@ -2,18 +2,11 @@ OC.L10N.register(
"comments",
{
"Comments" : "تعليقات",
"You commented" : "قمت بكتابة تعليق",
"%1$s commented" : "%1$s كتب تعليق",
"You commented on %1$s" : "لقد علقت على %1$s",
"You commented on {file}" : "علقت على {file}",
"%1$s commented on %2$s" : "%1$s كتب تعليق على %2$s",
"{author} commented on {file}" : "{author} علّق على {file}",
"<strong>Comments</strong> for files" : "<strong>تعليقات</strong> على الملفات",
"Edit comment" : "تعديل التعليق",
"Delete comment" : "حذف التعليق",
"New comment …" : "تعليق جديد",
"Delete comment" : "حذف التعليق",
"Post" : "ارسال",
"Cancel" : "إلغاء",
"Edit comment" : "تعديل التعليق",
"[Deleted user]" : "[مستخدم محذوف]",
"No comments yet, start the conversation!" : "لا يوجد تعليقات, ابدأ النقاش الآن!",
"More comments …" : "مزيد من التعليقات...",
@@ -21,7 +14,13 @@ OC.L10N.register(
"Allowed characters {count} of {max}" : "عدد الأحرف المسموح بها {count} من {max}",
"Error occurred while updating comment with id {id}" : "حصل خطأ أثناء تعديل التعليق رقم {id}",
"Error occurred while posting comment" : "حصل خطأ أثناء إرسال التعليق",
"_%n unread comment_::_%n unread comments_" : ["%n تعليق غير مقروء","%n تعليق غير مقروء","تعليقان غير مقروءة","%n تعليقات غير مقروء","%n تعليق غير مقروء","%n تعليق غير مقروء"],
"Comment" : "تعليق"
"Comment" : "تعليق",
"You commented" : "قمت بكتابة تعليق",
"%1$s commented" : "%1$s كتب تعليق",
"You commented on {file}" : "علقت على {file}",
"%1$s commented on %2$s" : "%1$s كتب تعليق على %2$s",
"{author} commented on {file}" : "{author} علّق على {file}",
"<strong>Comments</strong> for files" : "<strong>تعليقات</strong> على الملفات",
"Unknown user" : "مستخدم غير معروف"
},
"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;");
+10 -11
View File
@@ -1,17 +1,10 @@
{ "translations": {
"Comments" : "تعليقات",
"You commented" : "قمت بكتابة تعليق",
"%1$s commented" : "%1$s كتب تعليق",
"You commented on %1$s" : "لقد علقت على %1$s",
"You commented on {file}" : "علقت على {file}",
"%1$s commented on %2$s" : "%1$s كتب تعليق على %2$s",
"{author} commented on {file}" : "{author} علّق على {file}",
"<strong>Comments</strong> for files" : "<strong>تعليقات</strong> على الملفات",
"Edit comment" : "تعديل التعليق",
"Delete comment" : "حذف التعليق",
"New comment …" : "تعليق جديد",
"Delete comment" : "حذف التعليق",
"Post" : "ارسال",
"Cancel" : "إلغاء",
"Edit comment" : "تعديل التعليق",
"[Deleted user]" : "[مستخدم محذوف]",
"No comments yet, start the conversation!" : "لا يوجد تعليقات, ابدأ النقاش الآن!",
"More comments …" : "مزيد من التعليقات...",
@@ -19,7 +12,13 @@
"Allowed characters {count} of {max}" : "عدد الأحرف المسموح بها {count} من {max}",
"Error occurred while updating comment with id {id}" : "حصل خطأ أثناء تعديل التعليق رقم {id}",
"Error occurred while posting comment" : "حصل خطأ أثناء إرسال التعليق",
"_%n unread comment_::_%n unread comments_" : ["%n تعليق غير مقروء","%n تعليق غير مقروء","تعليقان غير مقروءة","%n تعليقات غير مقروء","%n تعليق غير مقروء","%n تعليق غير مقروء"],
"Comment" : "تعليق"
"Comment" : "تعليق",
"You commented" : "قمت بكتابة تعليق",
"%1$s commented" : "%1$s كتب تعليق",
"You commented on {file}" : "علقت على {file}",
"%1$s commented on %2$s" : "%1$s كتب تعليق على %2$s",
"{author} commented on {file}" : "{author} علّق على {file}",
"<strong>Comments</strong> for files" : "<strong>تعليقات</strong> على الملفات",
"Unknown user" : "مستخدم غير معروف"
},"pluralForm" :"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;"
}
+15 -12
View File
@@ -2,20 +2,11 @@ OC.L10N.register(
"comments",
{
"Comments" : "Comentarios",
"You commented" : "Comentesti",
"%1$s commented" : "%1$s comentó",
"{author} commented" : "{author} comentó",
"You commented on %1$s" : "Comentesti en %1$s",
"You commented on {file}" : "Comentesti en {file}",
"%1$s commented on %2$s" : "%1$s comentó en %2$s",
"{author} commented on {file}" : "{autor} comentó en {ficheru}",
"<strong>Comments</strong> for files" : "<strong>Comentarios</strong> pa ficheros",
"{user} mentioned you in a comment on “{file}”" : "{user} mentóte nun comentariu de «{file}»",
"Edit comment" : "Editar comentariu",
"Delete comment" : "Desaniciar comentariu",
"New comment …" : "Comentariu nuevu...",
"Delete comment" : "Desaniciar comentariu",
"Post" : "Espublizar",
"Cancel" : "Encaboxar",
"Edit comment" : "Editar comentariu",
"[Deleted user]" : "[Usuariu desaniciáu]",
"No comments yet, start the conversation!" : "Entá nun hai comentarios. ¡Entama una conversación!",
"More comments …" : "Más comentarios...",
@@ -25,6 +16,18 @@ OC.L10N.register(
"Error occurred while posting comment" : "Asocedieron fallos entrín s'espublizaba'l comentariu",
"_%n unread comment_::_%n unread comments_" : ["%n comentariu ensin lleer","%n comentarios ensin lleer"],
"Comment" : "Comentariu",
"%1$s mentioned you in a comment on “%2$s”" : "%1$s mentóte nun comentariu de «%2$s»"
"You commented" : "Comentesti",
"%1$s commented" : "%1$s comentó",
"{author} commented" : "{author} comentó",
"You commented on %1$s" : "Comentesti en %1$s",
"You commented on {file}" : "Comentesti en {file}",
"%1$s commented on %2$s" : "%1$s comentó en %2$s",
"{author} commented on {file}" : "{autor} comentó en {ficheru}",
"<strong>Comments</strong> for files" : "<strong>Comentarios</strong> pa ficheros",
"%1$s mentioned you in a comment on “%2$s”" : "%1$s mentóte nun comentariu de «%2$s»",
"{user} mentioned you in a comment on “{file}”" : "{user} mentóte nun comentariu de «{file}»",
"Unknown user" : "Usuariu desconocíu",
"A (now) deleted user mentioned you in a comment on “%s”" : "Un usuariu (agora) desaniciáu mentóte nun comentariu de «%s»",
"A (now) deleted user mentioned you in a comment on “{file}”" : "Un usuariu (agora) desaniciáu mentóte nun comentariu de «{file}»"
},
"nplurals=2; plural=(n != 1);");
+15 -12
View File
@@ -1,19 +1,10 @@
{ "translations": {
"Comments" : "Comentarios",
"You commented" : "Comentesti",
"%1$s commented" : "%1$s comentó",
"{author} commented" : "{author} comentó",
"You commented on %1$s" : "Comentesti en %1$s",
"You commented on {file}" : "Comentesti en {file}",
"%1$s commented on %2$s" : "%1$s comentó en %2$s",
"{author} commented on {file}" : "{autor} comentó en {ficheru}",
"<strong>Comments</strong> for files" : "<strong>Comentarios</strong> pa ficheros",
"{user} mentioned you in a comment on “{file}”" : "{user} mentóte nun comentariu de «{file}»",
"Edit comment" : "Editar comentariu",
"Delete comment" : "Desaniciar comentariu",
"New comment …" : "Comentariu nuevu...",
"Delete comment" : "Desaniciar comentariu",
"Post" : "Espublizar",
"Cancel" : "Encaboxar",
"Edit comment" : "Editar comentariu",
"[Deleted user]" : "[Usuariu desaniciáu]",
"No comments yet, start the conversation!" : "Entá nun hai comentarios. ¡Entama una conversación!",
"More comments …" : "Más comentarios...",
@@ -23,6 +14,18 @@
"Error occurred while posting comment" : "Asocedieron fallos entrín s'espublizaba'l comentariu",
"_%n unread comment_::_%n unread comments_" : ["%n comentariu ensin lleer","%n comentarios ensin lleer"],
"Comment" : "Comentariu",
"%1$s mentioned you in a comment on “%2$s”" : "%1$s mentóte nun comentariu de «%2$s»"
"You commented" : "Comentesti",
"%1$s commented" : "%1$s comentó",
"{author} commented" : "{author} comentó",
"You commented on %1$s" : "Comentesti en %1$s",
"You commented on {file}" : "Comentesti en {file}",
"%1$s commented on %2$s" : "%1$s comentó en %2$s",
"{author} commented on {file}" : "{autor} comentó en {ficheru}",
"<strong>Comments</strong> for files" : "<strong>Comentarios</strong> pa ficheros",
"%1$s mentioned you in a comment on “%2$s”" : "%1$s mentóte nun comentariu de «%2$s»",
"{user} mentioned you in a comment on “{file}”" : "{user} mentóte nun comentariu de «{file}»",
"Unknown user" : "Usuariu desconocíu",
"A (now) deleted user mentioned you in a comment on “%s”" : "Un usuariu (agora) desaniciáu mentóte nun comentariu de «%s»",
"A (now) deleted user mentioned you in a comment on “{file}”" : "Un usuariu (agora) desaniciáu mentóte nun comentariu de «{file}»"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}
+20 -17
View File
@@ -2,6 +2,20 @@ OC.L10N.register(
"comments",
{
"Comments" : "Коментари",
"New comment …" : "Нов коментар...",
"Delete comment" : "Изтрий коментар",
"Post" : "Публикация",
"Cancel" : "Отказ",
"Edit comment" : "Редактирай коментра",
"[Deleted user]" : "[Изтрит потребител]",
"No comments yet, start the conversation!" : "Все-още няма коментари, започни разговор!",
"More comments …" : "Още коментари...",
"Save" : "Запазване",
"Allowed characters {count} of {max}" : "Позволени символи {count} от {max}",
"Error occurred while updating comment with id {id}" : "Възникна грешка по време на обновяване на коментар с код {id}",
"Error occurred while posting comment" : "Възникна грешка по време на изпращане на коментар",
"_%n unread comment_::_%n unread comments_" : ["%n непрочетен коментар","%n непрочетени коментари"],
"Comment" : "Коментар",
"You commented" : "Вие коментирахте",
"%1$s commented" : "%1$s коментира",
"{author} commented" : "{author} коментира",
@@ -10,23 +24,12 @@ OC.L10N.register(
"%1$s commented on %2$s" : "%1$s коментиран за %2$s",
"{author} commented on {file}" : "{author} коментира за {file}",
"<strong>Comments</strong> for files" : "<strong>Коментари</strong> за файлове",
"You were mentioned on “{file}”, in a comment by a user that has since been deleted" : "Бяхте споменат/а към “{file}”, в коментар от потребител, който вече е изтрит",
"{user} mentioned you in a comment on “{file}”" : "{user} те спомена в коментар за “{file}”",
"Edit comment" : "Редактирай коментра",
"Delete comment" : "Изтрий коментар",
"New comment …" : "Нов коментар...",
"Post" : "Публикация",
"Cancel" : "Отказ",
"[Deleted user]" : "[Изтрит потребител]",
"No comments yet, start the conversation!" : "Все още няма коментари, започнете разговор!",
"More comments …" : "Още коментари...",
"Save" : "Запазване",
"Allowed characters {count} of {max}" : "Позволени символи {count} от {max}",
"Error occurred while updating comment with id {id}" : "Възникна грешка по време на обновяване на коментар с код {id}",
"Error occurred while posting comment" : "Възникна грешка по време на изпращане на коментар",
"_%n unread comment_::_%n unread comments_" : ["%n непрочетен коментар","%n непрочетени коментари"],
"Comment" : "Коментар",
"You were mentioned on “%s”, in a comment by a user that has since been deleted" : "Бяхте споменат/а на “%s”, в коментар от потребител, който вече е изтрит",
"%1$s mentioned you in a comment on “%2$s”" : "%1$s те спомена в коментар за “%2$s”"
"You were mentioned on “{file}”, in a comment by a user that has since been deleted" : "Бяхте споменат/а към “{file}”, в коментар от потребител, който вече е изтрит",
"%1$s mentioned you in a comment on “%2$s”" : "%1$s те спомена в коментар за “%2$s”",
"{user} mentioned you in a comment on “{file}”" : "{user} те спомена в коментар за “{file}”",
"Unknown user" : "Непознат потребител",
"A (now) deleted user mentioned you in a comment on “%s”" : "(Токущо) изтрит потребител те коментира в “%s”",
"A (now) deleted user mentioned you in a comment on “{file}”" : "(Токущо) изтрит потребител те спомена в коментар за “{file}”"
},
"nplurals=2; plural=(n != 1);");
+20 -17
View File
@@ -1,5 +1,19 @@
{ "translations": {
"Comments" : "Коментари",
"New comment …" : "Нов коментар...",
"Delete comment" : "Изтрий коментар",
"Post" : "Публикация",
"Cancel" : "Отказ",
"Edit comment" : "Редактирай коментра",
"[Deleted user]" : "[Изтрит потребител]",
"No comments yet, start the conversation!" : "Все-още няма коментари, започни разговор!",
"More comments …" : "Още коментари...",
"Save" : "Запазване",
"Allowed characters {count} of {max}" : "Позволени символи {count} от {max}",
"Error occurred while updating comment with id {id}" : "Възникна грешка по време на обновяване на коментар с код {id}",
"Error occurred while posting comment" : "Възникна грешка по време на изпращане на коментар",
"_%n unread comment_::_%n unread comments_" : ["%n непрочетен коментар","%n непрочетени коментари"],
"Comment" : "Коментар",
"You commented" : "Вие коментирахте",
"%1$s commented" : "%1$s коментира",
"{author} commented" : "{author} коментира",
@@ -8,23 +22,12 @@
"%1$s commented on %2$s" : "%1$s коментиран за %2$s",
"{author} commented on {file}" : "{author} коментира за {file}",
"<strong>Comments</strong> for files" : "<strong>Коментари</strong> за файлове",
"You were mentioned on “{file}”, in a comment by a user that has since been deleted" : "Бяхте споменат/а към “{file}”, в коментар от потребител, който вече е изтрит",
"{user} mentioned you in a comment on “{file}”" : "{user} те спомена в коментар за “{file}”",
"Edit comment" : "Редактирай коментра",
"Delete comment" : "Изтрий коментар",
"New comment …" : "Нов коментар...",
"Post" : "Публикация",
"Cancel" : "Отказ",
"[Deleted user]" : "[Изтрит потребител]",
"No comments yet, start the conversation!" : "Все още няма коментари, започнете разговор!",
"More comments …" : "Още коментари...",
"Save" : "Запазване",
"Allowed characters {count} of {max}" : "Позволени символи {count} от {max}",
"Error occurred while updating comment with id {id}" : "Възникна грешка по време на обновяване на коментар с код {id}",
"Error occurred while posting comment" : "Възникна грешка по време на изпращане на коментар",
"_%n unread comment_::_%n unread comments_" : ["%n непрочетен коментар","%n непрочетени коментари"],
"Comment" : "Коментар",
"You were mentioned on “%s”, in a comment by a user that has since been deleted" : "Бяхте споменат/а на “%s”, в коментар от потребител, който вече е изтрит",
"%1$s mentioned you in a comment on “%2$s”" : "%1$s те спомена в коментар за “%2$s”"
"You were mentioned on “{file}”, in a comment by a user that has since been deleted" : "Бяхте споменат/а към “{file}”, в коментар от потребител, който вече е изтрит",
"%1$s mentioned you in a comment on “%2$s”" : "%1$s те спомена в коментар за “%2$s”",
"{user} mentioned you in a comment on “{file}”" : "{user} те спомена в коментар за “{file}”",
"Unknown user" : "Непознат потребител",
"A (now) deleted user mentioned you in a comment on “%s”" : "(Токущо) изтрит потребител те коментира в “%s”",
"A (now) deleted user mentioned you in a comment on “{file}”" : "(Токущо) изтрит потребител те спомена в коментар за “{file}”"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}
+22 -22
View File
@@ -2,6 +2,20 @@ OC.L10N.register(
"comments",
{
"Comments" : "Comentaris",
"New comment …" : "Nou comentari...",
"Delete comment" : "Esborrar comentari",
"Post" : "Publica",
"Cancel" : "Cancel·la",
"Edit comment" : "Editar comentari",
"[Deleted user]" : "[usuari Esborrat]",
"No comments yet, start the conversation!" : "Encara no hi ha comentaris. Comenceu la conversa!",
"More comments …" : "Més comentaris...",
"Save" : "Desa",
"Allowed characters {count} of {max}" : "{count} caràcters permesos de {max}",
"Error occurred while updating comment with id {id}" : "Hi ha hagut un error en actualitzar el comentari amb id {id}",
"Error occurred while posting comment" : "Hi ha hagut un error en publicar el comentari",
"_%n unread comment_::_%n unread comments_" : ["%n comentari no llegit","%n comentaris no llegits"],
"Comment" : "Comentari",
"You commented" : "Heu comentat",
"%1$s commented" : "%1$s ha comentat",
"{author} commented" : "{author} ha comentat",
@@ -9,27 +23,13 @@ OC.L10N.register(
"You commented on {file}" : "Heu comentat a {file}",
"%1$s commented on %2$s" : "%1$s ha comentat a %2$s",
"{author} commented on {file}" : "{author} ha comentat a {file}",
"<strong>Comments</strong> for files" : "<strong>Comentaris</strong> per fitxers",
"You were mentioned on “{file}”, in a comment by a user that has since been deleted" : "Heu estat esmentats a \"{file}\" en un comentari d'un usuari que ja no existeix",
"{user} mentioned you in a comment on “{file}”" : "{user} us ha esmentat en un comentari de “{file}”",
"Files app plugin to add comments to files" : "Connexió de laplicació de fitxers per afegir comentaris als fitxers",
"Edit comment" : "Edita comentari",
"Delete comment" : "Suprimeix comentari",
"New comment " : "Nou comentari...",
"Post" : "Publica",
"Cancel" : "Cancel·la",
"[Deleted user]" : "[Usuari suprimit]",
"No comments yet, start the conversation!" : "Encara no hi ha comentaris. Enceteu la conversa!",
"More comments …" : "Més comentaris...",
"Save" : "Desa",
"Allowed characters {count} of {max}" : "{count} caràcters permesos de {max}",
"Error occurred while retrieving comment with ID {id}" : "S'ha produït un error en recuperar el comentari amb l'ID {id}",
"Error occurred while updating comment with id {id}" : "Hi ha hagut un error en actualitzar el comentari amb id {id}",
"Error occurred while posting comment" : "Hi ha hagut un error en publicar el comentari",
"_%n unread comment_::_%n unread comments_" : ["%n comentari no llegit","%n comentaris no llegits"],
"_1 new comment_::_{unread} new comments_" : ["1 comentari nou","{unread} comentaris nous"],
"Comment" : "Comentari",
"You were mentioned on “%s”, in a comment by a user that has since been deleted" : "Hau estat esmentats a \"%s\" en un comentari d'un usuari que ja no existeix",
"%1$s mentioned you in a comment on “%2$s”" : "%1$s us ha esmentat en un comentari a “%2$s”"
"<strong>Comments</strong> for files" : "<strong>Comentaris</strong> per arxius",
"You were mentioned on “%s”, in a comment by a user that has since been deleted" : "Has estat mencionat a \"%s\" en un comentari d'un usuari que ja no existeix",
"You were mentioned on “{file}”, in a comment by a user that has since been deleted" : "Has estat mencionat a \"{file}\" en un comentari d'un usuari que ja no existeix",
"%1$s mentioned you in a comment on “%2$s”" : "%1$s us ha nomenat en un comentari a “%2$s”",
"{user} mentioned you in a comment on “{file}”" : "{user} us ha nomenat en un comentari de “{file}”",
"Unknown user" : "Usuari desconegut",
"A (now) deleted user mentioned you in a comment on “%s”" : "Un usuari (ara) esborrat us ha nomenat en un comentari a “%s”",
"A (now) deleted user mentioned you in a comment on “{file}”" : "Un usuari (ara) esborrat us ha nomenat en un comentari de “{file}”"
},
"nplurals=2; plural=(n != 1);");
+22 -22
View File
@@ -1,5 +1,19 @@
{ "translations": {
"Comments" : "Comentaris",
"New comment …" : "Nou comentari...",
"Delete comment" : "Esborrar comentari",
"Post" : "Publica",
"Cancel" : "Cancel·la",
"Edit comment" : "Editar comentari",
"[Deleted user]" : "[usuari Esborrat]",
"No comments yet, start the conversation!" : "Encara no hi ha comentaris. Comenceu la conversa!",
"More comments …" : "Més comentaris...",
"Save" : "Desa",
"Allowed characters {count} of {max}" : "{count} caràcters permesos de {max}",
"Error occurred while updating comment with id {id}" : "Hi ha hagut un error en actualitzar el comentari amb id {id}",
"Error occurred while posting comment" : "Hi ha hagut un error en publicar el comentari",
"_%n unread comment_::_%n unread comments_" : ["%n comentari no llegit","%n comentaris no llegits"],
"Comment" : "Comentari",
"You commented" : "Heu comentat",
"%1$s commented" : "%1$s ha comentat",
"{author} commented" : "{author} ha comentat",
@@ -7,27 +21,13 @@
"You commented on {file}" : "Heu comentat a {file}",
"%1$s commented on %2$s" : "%1$s ha comentat a %2$s",
"{author} commented on {file}" : "{author} ha comentat a {file}",
"<strong>Comments</strong> for files" : "<strong>Comentaris</strong> per fitxers",
"You were mentioned on “{file}”, in a comment by a user that has since been deleted" : "Heu estat esmentats a \"{file}\" en un comentari d'un usuari que ja no existeix",
"{user} mentioned you in a comment on “{file}”" : "{user} us ha esmentat en un comentari de “{file}”",
"Files app plugin to add comments to files" : "Connexió de laplicació de fitxers per afegir comentaris als fitxers",
"Edit comment" : "Edita comentari",
"Delete comment" : "Suprimeix comentari",
"New comment " : "Nou comentari...",
"Post" : "Publica",
"Cancel" : "Cancel·la",
"[Deleted user]" : "[Usuari suprimit]",
"No comments yet, start the conversation!" : "Encara no hi ha comentaris. Enceteu la conversa!",
"More comments …" : "Més comentaris...",
"Save" : "Desa",
"Allowed characters {count} of {max}" : "{count} caràcters permesos de {max}",
"Error occurred while retrieving comment with ID {id}" : "S'ha produït un error en recuperar el comentari amb l'ID {id}",
"Error occurred while updating comment with id {id}" : "Hi ha hagut un error en actualitzar el comentari amb id {id}",
"Error occurred while posting comment" : "Hi ha hagut un error en publicar el comentari",
"_%n unread comment_::_%n unread comments_" : ["%n comentari no llegit","%n comentaris no llegits"],
"_1 new comment_::_{unread} new comments_" : ["1 comentari nou","{unread} comentaris nous"],
"Comment" : "Comentari",
"You were mentioned on “%s”, in a comment by a user that has since been deleted" : "Hau estat esmentats a \"%s\" en un comentari d'un usuari que ja no existeix",
"%1$s mentioned you in a comment on “%2$s”" : "%1$s us ha esmentat en un comentari a “%2$s”"
"<strong>Comments</strong> for files" : "<strong>Comentaris</strong> per arxius",
"You were mentioned on “%s”, in a comment by a user that has since been deleted" : "Has estat mencionat a \"%s\" en un comentari d'un usuari que ja no existeix",
"You were mentioned on “{file}”, in a comment by a user that has since been deleted" : "Has estat mencionat a \"{file}\" en un comentari d'un usuari que ja no existeix",
"%1$s mentioned you in a comment on “%2$s”" : "%1$s us ha nomenat en un comentari a “%2$s”",
"{user} mentioned you in a comment on “{file}”" : "{user} us ha nomenat en un comentari de “{file}”",
"Unknown user" : "Usuari desconegut",
"A (now) deleted user mentioned you in a comment on “%s”" : "Un usuari (ara) esborrat us ha nomenat en un comentari a “%s”",
"A (now) deleted user mentioned you in a comment on “{file}”" : "Un usuari (ara) esborrat us ha nomenat en un comentari de “{file}”"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
}

Some files were not shown because too many files have changed in this diff Show More