Compare commits

...

176 Commits

Author SHA1 Message Date
Frank Karlitschek
9aae21db79 5.0.5 2013-04-10 02:14:16 +02:00
Jan-Christoph Borchardt
536117da2a apply navigation hover effect directly to img and span, cleaner code 2013-04-18 10:03:14 +02:00
Brice Maron
29054c27c9 Warn when we do an upgrade 2013-04-17 22:03:05 +02:00
Jan-Christoph Borchardt
207bf4bffe additional comments 2013-04-17 19:44:20 +02:00
Jan-Christoph Borchardt
4e11814a0c fix navigation hover effect, documentation 2013-04-17 19:44:07 +02:00
Thomas Tanghus
32667f8c38 Remove not null constraint. Fix #2976 2013-04-17 19:18:17 +02:00
Thomas Müller
1c06bec262 Merge pull request #2967 from Mirodin/patch-6
Update de_DE.php
2013-04-17 02:29:34 -07:00
Thomas Müller
a82965edf2 Merge pull request #2965 from Mirodin/patch-5
Update de.php
2013-04-17 02:29:02 -07:00
Mirodin
76f12567be Update de_DE.php 2013-04-17 11:54:56 +03:00
Mirodin
d7cbf45d15 Update de.php
Fixed a translation issue
2013-04-17 11:53:17 +03:00
Bart Visscher
05a2f31352 Merge pull request #2960 from owncloud/always_load_file_cache_hooks_first_stable5
always connect file cache updater hooks first
2013-04-17 00:32:45 -07:00
Jörn Friedrich Dreyer
811d649262 always connect file cache updater hooks first 2013-04-17 08:21:33 +02:00
Frank Karlitschek
6e32fc1db7 Merge pull request #2945 from owncloud/improved_quota_calc
Improved free space calculation for trash and versions
2013-04-16 19:55:32 -07:00
Björn Schießle
e718a728c4 adapt free space calculation to the way it is done for the trash bin 2013-04-16 13:52:46 +02:00
Björn Schießle
a065ae5db2 improved free space calculation if no quota is set, discussed in #2936 2013-04-16 13:51:53 +02:00
Bernhard Posselt
623db8549e also show black background on links that are active, fixes the news app that doesnt show the bg for folders correctly 2013-04-15 21:07:50 +02:00
Jan-Christoph Borchardt
16ef7c62dc Merge pull request #2931 from owncloud/info_message_trash_bin
write a info message to the log if a file gets removed from the trash bin automatically
2013-04-15 11:16:43 -07:00
Björn Schießle
0978ebd195 add explenation of the expire function to the apps description 2013-04-15 11:42:50 +02:00
Björn Schießle
1ddfefed3f write a info message to the log if a file gets removed from the trash bin automatically 2013-04-15 10:34:38 +02:00
Arthur Schiwon
16b62c697f allow Storages to join MountPoint initialization 2013-04-15 10:28:14 +02:00
Jan-Christoph Borchardt
f70b1c1b0d add .disabled class so it can be used for simple a buttons as well 2013-04-14 22:07:07 +02:00
raghunayyar
b400c29944 Add span tag while enabling or disbling apps as well. 2013-04-13 20:08:25 +05:30
Lukas Reschke
86d8b831f2 Add a name to the version parameter
Without an additional name it's nearly impossible to write positive security model based rules since the parameter name isn't defined.
2013-04-13 15:49:15 +02:00
Thomas Mueller
5fbb8b374d more accurate safe_mode check - refs #2258 2013-04-13 01:16:45 +02:00
Bernhard Posselt
0a3e87c890 used oc version 5.0.3 2013-04-13 01:15:35 +02:00
Bernhard Posselt
2220802cdd added yet another test for the verion compare check due to mail 2013-04-13 01:15:35 +02:00
Jan-Christoph Borchardt
0ff7aa4436 add styles for disabled input fields 2013-04-12 19:14:09 +02:00
Jan-Christoph Borchardt
5e817584db use proper sans-serif font-stack 2013-04-12 19:10:20 +02:00
Bernhard Posselt
fbcb4b2673 Merge pull request #2899 from owncloud/stable5-backport-buttonfix
dont overwrite background image when hovering over button
2013-04-12 09:44:13 -07:00
Bernhard Posselt
edae196f34 dont overwrite background image when hovering over button 2013-04-12 15:41:37 +02:00
Bernhard Posselt
11dcc29c0c Merge pull request #2867 from owncloud/cleanup_after_delUser
Cleanup database after del user
2013-04-11 05:00:44 -07:00
Björn Schießle
d068325bdb cleanup the trash bin tables in the database after a user was deleted 2013-04-11 12:37:52 +02:00
Björn Schießle
6dc66e14fb remove used space for versions from db is a user was deleted 2013-04-11 12:36:08 +02:00
raghunayyar
30d5c70180 Using max-width instead of width for filename. 2013-04-11 13:55:31 +05:30
raghunayyar
e9c3caeb9b Adds a fixed width to the filename to prevent horizontal scroll. 2013-04-11 13:55:11 +05:30
raghunayyar
9a0344f1d5 The Opacity for the navigation loads fine for icon and App name. 2013-04-11 11:00:35 +05:30
raghunayyar
33b27362ff Long Application Names are ellipsis correctly. 2013-04-11 10:59:46 +05:30
Frank Karlitschek
15c50017cc 5.0.5 RC1 2013-04-09 20:04:37 +02:00
Frank Karlitschek
c43e33cdf5 5.0.4 2013-04-09 18:01:26 +02:00
Robin Appelman
ef1481c7bb Fix touch for creating new files 2013-04-10 14:52:56 +02:00
Robin Appelman
892d85556b Add the quota change listeners to newly added user entries in the user list 2013-04-10 14:50:42 +02:00
Frank Karlitschek
5fb891e20a Merge pull request #2828 from owncloud/trashbin_fixes
Trashbin fixes
2013-04-10 01:07:17 -07:00
Frank Karlitschek
c241985f04 5.0.4 RC 2013-04-09 16:59:03 +02:00
Lukas Reschke
9a4fe09979 Use a more random source... 2013-04-10 00:15:44 +02:00
Bart Visscher
e26cdc4cdd Suppress the notice from the nullbyte check 2013-04-09 22:20:48 +02:00
Björn Schießle
317b00988a size of the trash bin could be incorrect, remove it for all users to enforce a recalculation during next usage. 2013-04-09 15:27:19 +02:00
Thomas Mueller
9159d55639 fixes #2743 - use public OC_User::getDisplayName instead of OC_User::determineDisplayName 2013-04-09 15:23:35 +02:00
Thomas Mueller
06ab314c15 fixes #2125 - the warning is now displayed with a disabled button 2013-04-09 15:18:19 +02:00
Björn Schießle
f26a4e0b80 only add filesize to trashbin size if the file was moved to the trash bin successfully 2013-04-09 15:16:15 +02:00
Robin Appelman
2c3d66c776 Users: fix "Other.." quota option for the default quota 2013-04-09 15:15:08 +02:00
Frank Karlitschek
aef66e06b3 Merge pull request #2818 from owncloud/fix_versioncheck
fix versioning check
2013-04-09 05:35:46 -07:00
kondou
67a84ad487 Fix #2730
Swap OC.dialogs.alert()'s parameters, so Error is shown
as its title.
2013-04-09 14:20:23 +02:00
Frank Karlitschek
440148aa1f fix versioning check 2013-04-09 13:13:52 +02:00
OpenLarry
b35148bbb6 fixes #2679 2013-04-09 13:02:35 +02:00
Lukas Reschke
5ef8762886 Merge pull request #2786 from owncloud/disable-archive-app
manually disable archive app for stable5 to fix upgrade problems
2013-04-09 03:04:46 -07:00
Thomas Mueller
b52666567a fixes #2792 - only touch if writable 2013-04-09 10:52:06 +02:00
Bernhard Posselt
1e580bf04b manually disable archive app for stable5 to fix upgrade problems 2013-04-08 15:53:43 +02:00
Bart Visscher
2a5599b3e0 Merge pull request #2614 from eMerzh/fix_internet_check
Improve internet connection check with proxy
2013-04-06 09:50:40 -07:00
Bernhard Posselt
f82799cf7d Merge pull request #2741 from owncloud/fix_2650
Make FileCache upgrade more robust, fixes #2650
2013-04-05 12:22:59 -07:00
root
e6d286b449 Proper CSS comment
CSS comments don't work like that.
2013-04-05 17:13:17 +02:00
Arthur Schiwon
dc3a7e09af Make FileCache upgrade more robust, fixes #2650 2013-04-05 11:27:08 +02:00
Lukas Reschke
5add001373 Unescape the update hint
Backport of 8000f9db74ef2890cac74a34132c2550e4be6f11, fixes #2676
2013-04-05 00:41:08 +03:00
Bernhard Posselt
5317e7071e Merge pull request #2680 from owncloud/fix_2666
PostgreSQL compatibility, fixes #2666
2013-04-03 13:06:40 -07:00
Arthur Schiwon
f5592cc88e Typo, fixes #2690 2013-04-03 20:06:33 +02:00
Arthur Schiwon
09f11c2679 PostreSQL compatibility, fixes #2666 2013-04-03 13:04:38 +02:00
Frank Karlitschek
db48f5302a 5.0.3 2013-04-03 00:53:09 +02:00
Bernhard Posselt
4cd4bbd489 Merge pull request #2665 from owncloud/backport-2275-app-styles
manually backport #2275 app styles to stable
2013-04-02 14:24:00 -07:00
Bernhard Posselt
7b42c20180 Merge pull request #2595 from owncloud/fix_part_file_ignoring_stable5
Fix part file ignoring stable5
2013-04-02 14:01:17 -07:00
Jan-Christoph Borchardt
835df6c177 manually backport #2275 app styles to stable 2013-04-02 22:20:46 +02:00
root
5268aadb62 Backport PR #2622 2013-04-02 21:13:09 +02:00
Frank Karlitschek
d7dccfb648 5.0.3 RC1 2013-04-02 19:14:24 +02:00
Frank Karlitschek
cc204a608a Merge pull request #2656 from owncloud/fix_2642
fix upgrade error for instances not upgraded from 4.5
2013-04-02 09:34:29 -07:00
Arthur Schiwon
22c8194cc8 fix upgrade error for instances not upgraded from 4.5 2013-04-02 16:25:12 +02:00
Frank Karlitschek
8231f657d9 Merge pull request #2641 from owncloud/fix_2612
Key must use less then 767 bytes long
2013-04-02 02:58:57 -07:00
Arthur Schiwon
4f9f5a41b1 Key must use less then 767 bytes long 2013-04-02 11:29:41 +02:00
Frank Karlitschek
5944ee6ebe 5.0.2 2013-04-02 11:23:47 +02:00
VicDeo
e1b6574ce7 Merge pull request #2625 from owncloud/fix_namespace_in_autoloader_stable5
Fix namespace in autoloader stable5
2013-03-31 06:10:47 -07:00
VicDeo
c16860e648 Remove space before parethesis 2013-03-31 16:51:54 +04:00
Lukas Reschke
d4a492d321 Show a warning in the installer if the used PHP version is vulnerable to the NULL Byte attack 2013-03-31 16:51:29 +04:00
Lukas Reschke
a004266b7c Check if the installed PHP version has a fix for the nullbyte vulnerability 2013-03-31 16:51:12 +04:00
Thomas Mueller
da96d1adb0 some basic unit test for loading classes 2013-03-31 16:50:29 +04:00
VicDeo
ed39e47c9d Remove leading and trailing backslashes in classname. Ref #2310 2013-03-31 16:49:43 +04:00
Thomas Tanghus
b9213cf451 User list: Keep array of available groups. Should fix #873 2013-03-29 20:45:35 +01:00
Brice Maron
f308b0e321 Improve internet connection check with proxy 2013-03-29 15:37:39 +00:00
Thomas Mueller
eeebf21fce fixes #1463 - file size is now displayed correctly in IE8 2013-03-29 13:50:53 +01:00
Thomas Mueller
75d944f96a fixes #1461 2013-03-29 13:50:53 +01:00
Jörn Friedrich Dreyer
9bfdfdf071 supress write hook for .part files 2013-03-28 12:21:00 +01:00
Jörn Friedrich Dreyer
2bb22d3aab ignore files in scanFile instead of scan to catch all occurences.
Conflicts:
	lib/files/cache/scanner.php
2013-03-28 12:21:00 +01:00
blizzz
4742d0eb94 Merge pull request #2602 from owncloud/fix_share_with_displayname
Fix share with displayname
2013-03-27 14:54:16 -07:00
Arthur Schiwon
c901709d53 Whitespaces 2013-03-27 21:18:19 +01:00
Arthur Schiwon
84bc4c175a Share Dialog: show Displayname instead of internal name 2013-03-27 21:17:58 +01:00
blizzz
4d50a21eb4 Merge pull request #2558 from owncloud/fix_cache_upgrade
Fix cache upgrade
2013-03-27 11:10:22 -07:00
blizzz
37971133f1 Merge pull request #2596 from owncloud/fix_files_external_displayname
Files External: show display names instead of internal user names in Set...
2013-03-27 11:06:49 -07:00
blizzz
c962f9db47 Merge pull request #2593 from owncloud/fix_userlist_append_displayname
Users: use DisplayName in the Display Name col when appending users
2013-03-27 10:47:52 -07:00
Jan-Christoph Borchardt
6333036a1a Merge pull request #2599 from owncloud/backport-2515-nav-scrollbar
Backport 2515 nav scrollbar
2013-03-27 09:19:06 -07:00
yannickoo
73758c1f78 Fixed typo 2013-03-27 17:13:06 +01:00
yannickoo
7e9e94d8d7 No Scrolling for more than approximately 10 Applications 2013-03-27 17:13:04 +01:00
Arthur Schiwon
07d0245336 Files External: show display names instead of internal user names in Settings UI 2013-03-27 14:33:35 +01:00
Arthur Schiwon
0bbac66ec5 Users: use DisplayName in the Display Name col when appending users 2013-03-27 14:05:00 +01:00
Arthur Schiwon
4411de0dbf Cache: on equal mtime also for equal size before keeping ETag, at least makes Unit Test happy 2013-03-26 23:42:00 +01:00
Thomas Mueller
871bbbba8a prevent to fire delete ajax a second time.
Before the click on a single file delete icon fired two different handlers - one of them is for multiple deletion only
2013-03-26 22:56:42 +01:00
Arthur Schiwon
4384cf70da Cache: Do not overwrite ETag when file did not change 2013-03-26 16:03:40 +01:00
Thomas Müller
e0cf61dfc8 Merge pull request #2272 from owncloud/fix_json_encoded_pubic_download_oc5
let public link download handle json encoded file lists [oc5]
2013-03-26 01:55:40 -07:00
Björn Schießle
2387fbd9dd Merge pull request #2562 from owncloud/update_mtime_after_sync
listen to touch hook to update the mtime after sync
2013-03-26 01:41:41 -07:00
Arthur Schiwon
0b6b5e807c Only prepare an SQL statement once. 2013-03-25 21:46:50 +01:00
Arthur Schiwon
b2b78228d6 Add PHPDoc 2013-03-25 21:45:55 +01:00
Arthur Schiwon
2e5829445f Adjust to Icewind's fix 2013-03-25 21:45:10 +01:00
Robin Appelman
e63a12a481 Cache: fix property path for getting legacy etag 2013-03-25 21:43:51 +01:00
Robin Appelman
56302ff9cf Port Icewind's fix I 2013-03-25 21:43:49 +01:00
Arthur Schiwon
707de3e644 Add Index to properties table for better performance on upgrade 2013-03-25 17:54:45 +01:00
Arthur Schiwon
19a65f6c3f Change LIMIT in DB query respectively remove where not necessary 2013-03-25 17:54:10 +01:00
Björn Schießle
011ab3a11c listen to touch hook to update the mtime after sync 2013-03-25 16:26:17 +01:00
Arthur Schiwon
ad62d89f2b Remove Debug output 2013-03-25 14:23:46 +01:00
Jörn Friedrich Dreyer
9b84c50f15 Merge pull request #2533 from owncloud/fix_sharing_updater
fix shared updated for rename action
2013-03-25 05:13:57 -07:00
Thomas Müller
01ffa519d5 Fixing author and copyright 2013-03-24 19:17:56 +01:00
Thomas Mueller
fe73b5919d some more test cases & fix on file name generation with index 2013-03-24 19:17:56 +01:00
Thomas Mueller
5ad7eb080e adding extension to slugified physical path 2013-03-24 19:17:55 +01:00
Thomas Müller
2ce8329503 Merge pull request #2531 from Mirodin/patch-5
Update de.php
2013-03-24 11:14:33 -07:00
Thomas Müller
83e5383912 Merge pull request #2532 from Mirodin/patch-6
Update de_DE.php
2013-03-24 11:13:25 -07:00
Bernhard Posselt
660d204cbf Merge pull request #2525 from owncloud/fix_db_queries
add backticks around table names
2013-03-23 05:39:01 -07:00
Bernhard Posselt
d091db4bc7 Merge pull request #2474 from owncloud/fix_2299
skip update if the recipient is the same user as the owner
2013-03-23 05:35:50 -07:00
Bernhard Posselt
d61e820285 Merge pull request #2538 from eMerzh/improve_pbm_detect
Improve detection of installations errors
2013-03-23 05:31:19 -07:00
Brice Maron
85613cc66c Improve detection of installations errors 2013-03-23 12:19:43 +01:00
Arthur Schiwon
0fb9cc3c25 Upgrade FileCache on ownCloud upgrade for all users with files 2013-03-22 23:33:40 +01:00
Björn Schießle
76e5ffaa92 the old path no longer exists after rename, update the parent folder instead 2013-03-22 16:20:40 +01:00
Mirodin
9a26b1e0a6 Update de_DE.php
Fixed some translation issues
2013-03-22 15:33:52 +01:00
Mirodin
bfd69dc8e0 Update de.php
Fixed some translation issues
2013-03-22 15:28:20 +01:00
Arthur Schiwon
0d075df15e Performance: prepare queries only once 2013-03-22 13:36:31 +01:00
Arthur Schiwon
c82f43ee55 Fix lost ETag on Cache Upgrade 2013-03-22 13:23:43 +01:00
Björn Schießle
0eaf141528 add backticks around table names 2013-03-22 12:47:43 +01:00
Arthur Schiwon
ee0dab1b13 LDAP: fix wrong return value 2013-03-20 13:17:40 +01:00
Björn Schießle
98ee292c93 fix indention 2013-03-20 12:58:39 +01:00
Björn Schießle
4ff5658475 skip update if the recipient is the same user as the owner, otherwise we run in a infinite loop for group shares 2013-03-20 12:45:24 +01:00
Thomas Mueller
7de540b8ee using rtrim 2013-03-19 17:00:48 +01:00
Thomas Mueller
9a41453254 fixes #2081 2013-03-19 17:00:35 +01:00
Jörn Friedrich Dreyer
707b319157 Merge pull request #2449 from owncloud/fix_npe
fix npe when createStorage() returns null
2013-03-19 07:48:54 -07:00
Bernhard Posselt
f7911412e0 Merge pull request #2444 from owncloud/fix_ldap_issues
Fix ldap issues
2013-03-19 06:20:33 -07:00
Jörn Friedrich Dreyer
1cb3872df0 fix npe when createStorage() returns null 2013-03-19 14:18:44 +01:00
Arthur Schiwon
432fb55d91 LDAP: specify appid when selecting from appconfig 2013-03-19 13:39:52 +01:00
Arthur Schiwon
98c5d10bb5 LDAP: remove unnecessary func call, was a leftover from earlier refactor 2013-03-19 13:29:09 +01:00
Thomas Tanghus
84a2be1aad Backport #2440 js parameter. 2013-03-19 13:13:11 +01:00
Thomas Tanghus
9e383db75b User list: Avoid dupes and better sorting. Fix #2420 2013-03-19 12:59:32 +01:00
Arthur Schiwon
c12b30f7a2 LDAP: check first whether group exists in this backend before doing other operations 2013-03-19 11:52:35 +01:00
Arthur Schiwon
5bf111e75f LDAP: check whether user exists for before trying to determine displayname 2013-03-19 11:16:57 +01:00
Arthur Schiwon
f42d98edab LDAP: avoid irritating log output 2013-03-19 00:23:59 +01:00
Arthur Schiwon
d392aa81c7 LDAP: user exists check on getHome, otherwise check will be performed with wrong configs on a multi LDAP server setup. 2013-03-19 00:23:35 +01:00
Frank Karlitschek
532e5463db backport https://github.com/owncloud/core/pull/2411 2013-03-17 22:17:24 +01:00
Robin Appelman
cfea3ce2d7 Cache: better rename hook for cache updater 2013-03-17 14:16:13 +01:00
Robin Appelman
2c76ee1c8b Close sessions when doing background jobs 2013-03-17 02:25:21 +01:00
Michael Gapczynski
9a2c1cbcc3 Merge pull request #2384 from owncloud/error-handling-upgrade-backport
Backport add error handling to the file cache upgrade
2013-03-16 13:17:01 -07:00
Michael Gapczynski
e6616ed758 Add error handling to the file cache upgrade 2013-03-16 15:22:27 -04:00
Ceri Davies
b51b41468d Correct emails when folders are shared.
itemType is never "dir"; it's either "file" or "folder".
2013-03-15 12:43:22 +01:00
Frank Karlitschek
6f86802a48 Merge pull request #2348 from owncloud/fix_version_db_query
Fix db query in versions app, add backticks
2013-03-15 03:37:35 -07:00
Björn Schießle
0c6c175d62 remove backticks around table names 2013-03-15 11:24:13 +01:00
Brice Maron
885b81ba23 Add backtick for trash app to prevent pg errors 2013-03-15 11:19:02 +01:00
Björn Schießle
fc86815a2c add backtick for db queries to prevent postgresql errors 2013-03-15 11:06:51 +01:00
Björn Schießle
6ca2abc108 create new version if the same file is uploaded again over the web interface, approved in #2317 2013-03-15 10:47:19 +01:00
Björn Schießle
0fe2f81a0c create new version if the same file is uploaded again over the web interface 2013-03-15 10:44:27 +01:00
Bernhard Posselt
2cd52e52c8 Merge pull request #2294 from owncloud/use_display_name_in_mail
use display name as sender for private link mails
2013-03-14 05:22:45 -07:00
Björn Schießle
d06fec658c use display name as sender for private link mails 2013-03-14 11:48:04 +01:00
Bernhard Posselt
049329588f Merge pull request #2276 from owncloud/fix_sharing_hooks_oc5
listen to the pre delete hook in the sharing app [oc5]
2013-03-13 10:16:14 -07:00
Jörn Friedrich Dreyer
09d3b9ef26 Merge pull request #2278 from owncloud/fix_2267_master
use OC_DB instead of MDB2
2013-03-13 10:09:39 -07:00
Björn Schießle
92ce2bf89b fix for #2267, use OC_DB instead of MDB2 2013-03-13 16:51:41 +01:00
Björn Schießle
ca93f6e1de don't show share action for the Shared folder, approved pull request #2265 2013-03-13 16:26:20 +01:00
Björn Schießle
d166471a46 we need to listen to the pre delete hook, otherwise the file is already gone 2013-03-13 15:36:02 +01:00
Björn Schießle
896c56996e let public link download handle json encoded file lists 2013-03-13 11:40:46 +01:00
Arthur Schiwon
6017ca5ddd LDAP: compatibility with Novell eDirectory UUID 2013-03-12 20:16:09 +01:00
Thomas Mueller
eedc1e76db enable UTF-8 charset on mssql
disable MDB2_PORTABILITY_EMPTY_TO_NULL for mssql to allow insert of empty string to no null fields
2013-03-12 20:01:40 +01:00
Thomas Mueller
510cbc4ff9 write error message to log file in case insert to file cache failed - took hours to find that the insert failed :-( 2013-03-12 20:01:40 +01:00
Thomas Mueller
9b9497bedf fixing various filesystem/storage unit tests on windows
fixing copy operation on mapper
2013-03-12 19:57:56 +01:00
Thomas Mueller
8846edd919 skip archive tests for now 2013-03-12 19:57:42 +01:00
Thomas Mueller
253f7ec932 adding //IGNORE to iconv to prevent nasty php warnings 2013-03-12 19:57:28 +01:00
Thomas Mueller
8bafcd1414 slug generates uniqid in case the file/folder name contains not one single valid character 2013-03-12 19:56:44 +01:00
Thomas Mueller
40bb805b83 indexed slug should be created based on logic path 2013-03-12 19:56:33 +01:00
icewind1991
00030a6c24 Merge pull request #2248 from otetard/bugfix/fix-public-link-file-sharing
Fix file sharing via public link for one particular file.
2013-03-12 11:49:08 -07:00
Olivier Tétard
2afece459a Fix file sharing via public link for one particular file.
Fix OC_Files::get() to not return the first character of the filename
if only one file is requested.
2013-03-12 11:53:41 +01:00
70 changed files with 1161 additions and 325 deletions

View File

@@ -12,3 +12,10 @@ OCP\App::addNavigationEntry( array( "id" => "files_index",
"name" => $l->t("Files") ));
OC_Search::registerProvider('OC_Search_Provider_File');
// cache hooks must be connected before all other apps.
// since 'files' is always loaded first the hooks need to be connected here
\OC_Hook::connect('OC_Filesystem', 'post_write', '\OC\Files\Cache\Updater', 'writeHook');
\OC_Hook::connect('OC_Filesystem', 'post_touch', '\OC\Files\Cache\Updater', 'touchHook');
\OC_Hook::connect('OC_Filesystem', 'post_delete', '\OC\Files\Cache\Updater', 'deleteHook');
\OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Updater', 'renameHook');

View File

@@ -84,7 +84,7 @@ table td.filename input.filename { width:100%; cursor:text; }
table td.filename a, table td.login, table td.logout, table td.download, table td.upload, table td.create, table td.delete { padding:.2em .5em .5em 0; }
table td.filename .nametext, .uploadtext, .modified { float:left; padding:.3em 0; }
/* TODO fix usability bug (accidental file/folder selection) */
table td.filename .nametext { overflow:hidden; text-overflow:ellipsis; }
table td.filename .nametext { overflow:hidden; text-overflow:ellipsis; max-width:800px; }
table td.filename .uploadtext { font-weight:normal; margin-left:.5em; }
table td.filename form { font-size:.85em; margin-left:3em; margin-right:3em; }

View File

@@ -112,7 +112,7 @@ var FileActions = {
addAction(name, action);
}
});
if(actions.Share){
if(actions.Share && !($('#dir').val() === '/' && file === 'Shared')){
addAction('Share', actions.Share);
}

View File

@@ -226,14 +226,14 @@ $(document).ready(function() {
OC.Notification.show(t('files','Your download is being prepared. This might take some time if the files are big.'));
// use special download URL if provided, e.g. for public shared files
if ( (downloadURL = document.getElementById("downloadURL")) ) {
window.location=downloadURL.value+"&download&files="+files;
window.location=downloadURL.value+"&download&files="+encodeURIComponent(fileslist);
} else {
window.location=OC.filePath('files', 'ajax', 'download.php') + '?'+ $.param({ dir: dir, files: fileslist });
}
return false;
});
$('.delete').click(function(event) {
$('.delete-selected').click(function(event) {
var files=getSelectedFiles('name');
event.preventDefault();
FileList.do_delete(files);
@@ -407,7 +407,9 @@ $(document).ready(function() {
$('tr').filterAttr('data-file',file.name).data('mime',file.mime).data('id',file.id);
var size = $('tr').filterAttr('data-file',file.name).find('td.filesize').text();
if(size==t('files','Pending')){
$('tr').filterAttr('data-file',file.name).find('td.filesize').text(file.size);
var sizeElement = $('tr').filterAttr('data-file',file.name).find('td.filesize');
sizeElement.text(simpleFileSize(file.size));
sizeElement.attr('title',humanFileSize(file.size));
}
//TODO update file upload size limit
FileList.loadingDone(file.name, file.id);
@@ -438,7 +440,9 @@ $(document).ready(function() {
$('tr').filterAttr('data-file',file.name).data('mime',file.mime).data('id',file.id);
var size = $('tr').filterAttr('data-file',file.name).find('td.filesize').text();
if(size==t('files','Pending')){
$('tr').filterAttr('data-file',file.name).find('td.filesize').text(file.size);
var sizeElement = $('tr').filterAttr('data-file',file.name).find('td.filesize');
sizeElement.text(simpleFileSize(file.size));
sizeElement.attr('title',humanFileSize(file.size));
}
//TODO update file upload size limit
FileList.loadingDone(file.name, file.id);
@@ -459,6 +463,10 @@ $(document).ready(function() {
// TODO: show nice progress bar in file row
},
progressall: function(e, data) {
//IE < 10 does not fire the necessary events for the progress bar.
if($.browser.msie && parseInt($.browser.version) < 10) {
return;
}
var progress = (data.loaded/data.total)*100;
$('#uploadprogressbar').progressbar('value',progress);
},
@@ -477,6 +485,11 @@ $(document).ready(function() {
if(data.dataType != 'iframe ') {
$('#upload input.stop').hide();
}
//IE < 10 does not fire the necessary events for the progress bar.
if($.browser.msie && parseInt($.browser.version) < 10) {
return;
}
$('#uploadprogressbar').progressbar('value',100);
$('#uploadprogressbar').fadeOut();
}
@@ -637,12 +650,19 @@ $(document).ready(function() {
localName=(localName.match(/:\/\/(.[^/]+)/)[1]).replace('www.','');
}
localName = getUniqueName(localName);
$('#uploadprogressbar').progressbar({value:0});
$('#uploadprogressbar').fadeIn();
//IE < 10 does not fire the necessary events for the progress bar.
if($.browser.msie && parseInt($.browser.version) < 10) {
} else {
$('#uploadprogressbar').progressbar({value:0});
$('#uploadprogressbar').fadeIn();
}
var eventSource=new OC.EventSource(OC.filePath('files','ajax','newfile.php'),{dir:$('#dir').val(),source:name,filename:localName});
eventSource.listen('progress',function(progress){
$('#uploadprogressbar').progressbar('value',progress);
if($.browser.msie && parseInt($.browser.version) < 10) {
} else {
$('#uploadprogressbar').progressbar('value',progress);
}
});
eventSource.listen('success',function(data){
var mime=data.mime;

View File

@@ -50,7 +50,7 @@
</div>
<div id="file_action_panel"></div>
<?php else:?>
<div class="crumb last"><?php p($l->t('You dont have write permissions here.'))?></div>
<div class="actions"><input type="button" disabled value="<?php p($l->t('You dont have write permissions here.'))?>"></div>
<input type="hidden" name="dir" value="<?php p($_['dir']) ?>" id="dir">
<?php endif;?>
<input type="hidden" name="permissions" value="<?php p($_['permissions']); ?>" id="permissions">
@@ -82,13 +82,13 @@
<?php if ($_['permissions'] & OCP\PERMISSION_DELETE): ?>
<!-- NOTE: Temporary fix to allow unsharing of files in root of Shared folder -->
<?php if ($_['dir'] == '/Shared'): ?>
<span class="selectedActions"><a href="" class="delete">
<span class="selectedActions"><a href="" class="delete-selected">
<?php p($l->t('Unshare'))?>
<img class="svg" alt="<?php p($l->t('Unshare'))?>"
src="<?php print_unescaped(OCP\image_path("core", "actions/delete.svg")); ?>" />
</a></span>
<?php else: ?>
<span class="selectedActions"><a href="" class="delete">
<span class="selectedActions"><a href="" class="delete-selected">
<?php p($l->t('Delete'))?>
<img class="svg" alt="<?php p($l->t('Delete'))?>"
src="<?php print_unescaped(OCP\image_path("core", "actions/delete.svg")); ?>" />

View File

@@ -32,6 +32,7 @@ $tmpl->assign('mounts', OC_Mount_Config::getSystemMountPoints());
$tmpl->assign('backends', OC_Mount_Config::getBackends());
$tmpl->assign('groups', OC_Group::getGroups());
$tmpl->assign('users', OCP\User::getUsers());
$tmpl->assign('userDisplayNames', OC_User::getDisplayNames());
$tmpl->assign('dependencies', OC_Mount_Config::checkDependencies());
$tmpl->assign('allowUserMounting', OCP\Config::getAppValue('files_external', 'allow_user_mounting', 'yes'));
return $tmpl->fetchPage();

View File

@@ -102,7 +102,7 @@
<option value="<?php p($user); ?>"
<?php if (isset($mount['applicable']['users']) && in_array($user, $mount['applicable']['users'])): ?>
selected="selected"
<?php endif; ?>><?php p($user); ?></option>
<?php endif; ?>><?php p($_['userDisplayNames'][$user]); ?></option>
<?php endforeach; ?>
</optgroup>
</select>

View File

@@ -12,7 +12,7 @@ OCP\Share::registerBackend('file', 'OC_Share_Backend_File');
OCP\Share::registerBackend('folder', 'OC_Share_Backend_Folder', 'file');
OCP\Util::addScript('files_sharing', 'share');
\OC_Hook::connect('OC_Filesystem', 'post_write', '\OC\Files\Cache\Shared_Updater', 'writeHook');
\OC_Hook::connect('OC_Filesystem', 'post_delete', '\OC\Files\Cache\Shared_Updater', 'deleteHook');
\OC_Hook::connect('OC_Filesystem', 'delete', '\OC\Files\Cache\Shared_Updater', 'deleteHook');
\OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Shared_Updater', 'renameHook');
\OC_Hook::connect('OCP\Share', 'post_shared', '\OC\Files\Cache\Shared_Updater', 'shareHook');
\OC_Hook::connect('OCP\Share', 'pre_unshare', '\OC\Files\Cache\Shared_Updater', 'shareHook');

View File

@@ -38,10 +38,12 @@ class Shared_Updater {
while (!empty($users)) {
$reshareUsers = array();
foreach ($users as $user) {
$etag = \OC\Files\Filesystem::getETag('');
\OCP\Config::setUserValue($user, 'files_sharing', 'etag', $etag);
// Look for reshares
$reshareUsers = array_merge($reshareUsers, \OCP\Share::getUsersItemShared('file', $info['fileid'], $user, true));
if ( $user !== $uidOwner ) {
$etag = \OC\Files\Filesystem::getETag('');
\OCP\Config::setUserValue($user, 'files_sharing', 'etag', $etag);
// Look for reshares
$reshareUsers = array_merge($reshareUsers, \OCP\Share::getUsersItemShared('file', $info['fileid'], $user, true));
}
}
$users = $reshareUsers;
}
@@ -66,8 +68,8 @@ class Shared_Updater {
* @param array $params
*/
static public function renameHook($params) {
self::correctFolders($params['oldpath']);
self::correctFolders($params['newpath']);
self::correctFolders(pathinfo($params['oldpath'], PATHINFO_DIRNAME));
}
/**
@@ -88,10 +90,12 @@ class Shared_Updater {
while (!empty($users)) {
$reshareUsers = array();
foreach ($users as $user) {
$etag = \OC\Files\Filesystem::getETag('');
\OCP\Config::setUserValue($user, 'files_sharing', 'etag', $etag);
// Look for reshares
$reshareUsers = array_merge($reshareUsers, \OCP\Share::getUsersItemShared('file', $params['fileSource'], $user, true));
if ($user !== $uidOwner) {
$etag = \OC\Files\Filesystem::getETag('');
\OCP\Config::setUserValue($user, 'files_sharing', 'etag', $etag);
// Look for reshares
$reshareUsers = array_merge($reshareUsers, \OCP\Share::getUsersItemShared('file', $params['fileSource'], $user, true));
}
}
$users = $reshareUsers;
}

View File

@@ -113,7 +113,13 @@ if (isset($path)) {
// Download the file
if (isset($_GET['download'])) {
if (isset($_GET['files'])) { // download selected files
OC_Files::get($path, $_GET['files'], $_SERVER['REQUEST_METHOD'] == 'HEAD' ? true : false);
$files = urldecode($_GET['files']);
$files_list = json_decode($files);
// in case we get only a single file
if ($files_list === NULL ) {
$files_list = array($files);
}
OC_Files::get($path, $files_list, $_SERVER['REQUEST_METHOD'] == 'HEAD' ? true : false);
} else {
OC_Files::get($dir, $file, $_SERVER['REQUEST_METHOD'] == 'HEAD' ? true : false);
}

View File

@@ -3,5 +3,7 @@
OC::$CLASSPATH['OCA\Files_Trashbin\Hooks'] = 'files_trashbin/lib/hooks.php';
OC::$CLASSPATH['OCA\Files_Trashbin\Trashbin'] = 'files_trashbin/lib/trash.php';
//Listen to delete file signal
OCP\Util::connectHook('OC_Filesystem', 'delete', "OCA\Files_Trashbin\Hooks", "remove_hook");
//Listen to delete user signal
OCP\Util::connectHook('OC_User', 'pre_deleteUser', "OCA\Files_Trashbin\Hooks", "deleteUser_hook");

View File

@@ -2,7 +2,20 @@
<info>
<id>files_trashbin</id>
<name>Deleted files</name>
<description>Keep a copy of deleted files so that they can be restored if needed</description>
<description>
ownCloud keeps a copy of your deleted files in case you need them again.
To make sure that the user doesn't run out of memory the deleted files app
manages the size of the deleted files for the user. By default deleted files
stay in the trash bin for 180 days. ownCloud checks the age of the files
every time a new files gets moved to the deleted files and remove all files
older than 180 days. The user can adjust this value in the config.php by
setting the "trashbin_retention_obligation" value.
Beside that the delted files app take care to never use more that 50% of
your currently available free space. If your deleted files exceed this limit
ownCloud deletes the oldest versions until it meets the memory usage limit
again.
</description>
<licence>AGPL</licence>
<author>Bjoern Schiessle</author>
<shipped>true</shipped>

View File

@@ -1,40 +1,10 @@
<?php
$installedVersion=OCP\Config::getAppValue('files_trashbin', 'installed_version');
// move versions to new directory
if (version_compare($installedVersion, '0.2', '<')) {
$datadir = \OCP\Config::getSystemValue('datadirectory').'/';
$users = \OCP\User::getUsers();
foreach ($users as $user) {
//create new folders
@mkdir($datadir.$user.'/files_trashbin/files');
@mkdir($datadir.$user.'/files_trashbin/versions');
@mkdir($datadir.$user.'/files_trashbin/keyfiles');
// move files to the new folders
if ($handle = opendir($datadir.$user.'/files_trashbin')) {
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != ".." && $file != 'files' && $file != 'versions' && $file != 'keyfiles') {
rename($datadir.$user.'/files_trashbin/'.$file,
$datadir.$user.'/files_trashbin/files/'.$file);
}
}
closedir($handle);
}
// move versions to the new folder
if ($handle = opendir($datadir.$user.'/versions_trashbin')) {
while (false !== ($file = readdir($handle))) {
rename($datadir.$user.'/versions_trashbin/'.$file,
$datadir.$user.'/files_trashbin/versions/'.$file);
}
closedir($handle);
}
@rmdir($datadir.$user.'/versions_trashbin');
}
if (version_compare($installedVersion, '0.4', '<')) {
//size of the trash bin could be incorrect, remove it for all users to
//enforce a recalculation during next usage.
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trashsize`');
$result = $query->execute();
}

View File

@@ -1 +1 @@
0.3
0.4

View File

@@ -43,7 +43,7 @@ if ($dir) {
} else {
$dirlisting = false;
$query = \OC_DB::prepare('SELECT `id`,`location`,`timestamp`,`type`,`mime` FROM `*PREFIX*files_trash` WHERE user = ?');
$query = \OC_DB::prepare('SELECT `id`,`location`,`timestamp`,`type`,`mime` FROM `*PREFIX*files_trash` WHERE `user` = ?');
$result = $query->execute(array($user))->fetchAll();
}

View File

@@ -42,4 +42,18 @@ class Hooks {
Trashbin::move2trash($path);
}
}
/**
* @brief clean up user specific settings if user gets deleted
* @param array with uid
*
* This function is connected to the pre_deleteUser signal of OC_Users
* to remove the used space for the trash bin stored in the database
*/
public static function deleteUser_hook($params) {
if( \OCP\App::isEnabled('files_trashbin') ) {
$uid = $params['uid'];
Trashbin::deleteUser($uid);
}
}
}

View File

@@ -61,10 +61,12 @@ class Trashbin {
if ( $trashbinSize === false || $trashbinSize < 0 ) {
$trashbinSize = self::calculateSize(new \OC\Files\View('/'. $user.'/files_trashbin'));
}
$trashbinSize += self::copy_recursive($file_path, 'files_trashbin/files/'.$deleted.'.d'.$timestamp, $view);
$sizeOfAddedFiles = self::copy_recursive($file_path, 'files_trashbin/files/'.$deleted.'.d'.$timestamp, $view);
if ( $view->file_exists('files_trashbin/files/'.$deleted.'.d'.$timestamp) ) {
$query = \OC_DB::prepare("INSERT INTO *PREFIX*files_trash (id,timestamp,location,type,mime,user) VALUES (?,?,?,?,?,?)");
$trashbinSize += $sizeOfAddedFiles;
$query = \OC_DB::prepare("INSERT INTO `*PREFIX*files_trash` (`id`,`timestamp`,`location`,`type`,`mime`,`user`) VALUES (?,?,?,?,?,?)");
$result = $query->execute(array($deleted, $timestamp, $location, $type, $mime, $user));
if ( !$result ) { // if file couldn't be added to the database than also don't store it in the trash bin.
$view->deleteAll('files_trashbin/files/'.$deleted.'.d'.$timestamp);
@@ -102,27 +104,8 @@ class Trashbin {
} else {
\OC_Log::write('files_trashbin', 'Couldn\'t move '.$file_path.' to the trash bin', \OC_log::ERROR);
}
// get available disk space for user
$quota = \OC_Preferences::getValue($user, 'files', 'quota');
if ( $quota === null || $quota === 'default') {
$quota = \OC_Appconfig::getValue('files', 'default_quota');
}
if ( $quota === null || $quota === 'none' ) {
$quota = \OC\Files\Filesystem::free_space('/') / count(\OCP\User::getUsers());
} else {
$quota = \OCP\Util::computerFileSize($quota);
}
// calculate available space for trash bin
$rootInfo = $view->getFileInfo('/files');
$free = $quota-$rootInfo['size']; // remaining free space for user
if ( $free > 0 ) {
$availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - $trashbinSize; // how much space can be used for versions
} else {
$availableSpace = $free-$trashbinSize;
}
$trashbinSize -= self::expire($availableSpace);
$trashbinSize -= self::expire($trashbinSize);
self::setTrashbinSize($user, $trashbinSize);
@@ -144,8 +127,8 @@ class Trashbin {
$trashbinSize = self::calculateSize(new \OC\Files\View('/'. $user.'/files_trashbin'));
}
if ( $timestamp ) {
$query = \OC_DB::prepare('SELECT location,type FROM *PREFIX*files_trash'
.' WHERE user=? AND id=? AND timestamp=?');
$query = \OC_DB::prepare('SELECT `location`,`type` FROM `*PREFIX*files_trash`'
.' WHERE `user`=? AND `id`=? AND `timestamp`=?');
$result = $query->execute(array($user,$filename,$timestamp))->fetchAll();
if ( count($result) != 1 ) {
\OC_Log::write('files_trashbin', 'trash bin database inconsistent!', \OC_Log::ERROR);
@@ -228,7 +211,7 @@ class Trashbin {
}
if ( $timestamp ) {
$query = \OC_DB::prepare('DELETE FROM *PREFIX*files_trash WHERE user=? AND id=? AND timestamp=?');
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=? AND `id`=? AND `timestamp`=?');
$query->execute(array($user,$filename,$timestamp));
}
@@ -259,7 +242,7 @@ class Trashbin {
}
if ( $timestamp ) {
$query = \OC_DB::prepare('DELETE FROM *PREFIX*files_trash WHERE user=? AND id=? AND timestamp=?');
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=? AND `id`=? AND `timestamp`=?');
$query->execute(array($user,$filename,$timestamp));
$file = $filename.'.d'.$timestamp;
} else {
@@ -335,16 +318,71 @@ class Trashbin {
}
/**
* clean up the trash bin
* @param max. available disk space for trashbin
* @brief deletes used space for trash bin in db if user was deleted
*
* @param type $uid id of deleted user
* @return result of db delete operation
*/
private static function expire($availableSpace) {
public static function deleteUser($uid) {
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trash` WHERE `user`=?');
$result = $query->execute(array($uid));
if ($result) {
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_trashsize` WHERE `user`=?');
return $query->execute(array($uid));
}
return false;
}
/**
* calculate remaining free space for trash bin
*
* @param $trashbinSize current size of the trash bin
* @return available free space for trash bin
*/
private static function calculateFreeSpace($trashbinSize) {
$softQuota = true;
$user = \OCP\User::getUser();
$quota = \OC_Preferences::getValue($user, 'files', 'quota');
$view = new \OC\Files\View('/'.$user);
if ( $quota === null || $quota === 'default') {
$quota = \OC_Appconfig::getValue('files', 'default_quota');
}
if ( $quota === null || $quota === 'none' ) {
$quota = \OC\Files\Filesystem::free_space('/');
$softQuota = false;
} else {
$quota = \OCP\Util::computerFileSize($quota);
}
// calculate available space for trash bin
// subtract size of files and current trash bin size from quota
if ($softQuota) {
$rootInfo = $view->getFileInfo('/files/');
$free = $quota-$rootInfo['size']; // remaining free space for user
if ( $free > 0 ) {
$availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - $trashbinSize; // how much space can be used for versions
} else {
$availableSpace = $free-$trashbinSize;
}
} else {
$availableSpace = $quota;
}
return $availableSpace;
}
/**
* clean up the trash bin
* @param current size of the trash bin
*/
private static function expire($trashbinSize) {
$user = \OCP\User::getUser();
$view = new \OC\Files\View('/'.$user);
$availableSpace = self::calculateFreeSpace($trashbinSize);
$size = 0;
$query = \OC_DB::prepare('SELECT location,type,id,timestamp FROM *PREFIX*files_trash WHERE user=?');
$query = \OC_DB::prepare('SELECT `location`,`type`,`id`,`timestamp` FROM `*PREFIX*files_trash` WHERE `user`=?');
$result = $query->execute(array($user))->fetchAll();
$retention_obligation = \OC_Config::getValue('trashbin_retention_obligation',
@@ -357,18 +395,20 @@ class Trashbin {
$filename = $r['id'];
if ( $r['timestamp'] < $limit ) {
$size += self::delete($filename, $timestamp);
\OC_Log::write('files_trashbin', 'remove "'.$filename.'" fom trash bin because it is older than '.$retention_obligation, \OC_log::INFO);
}
}
$availableSpace = $availableSpace + $size;
// if size limit for trash bin reached, delete oldest files in trash bin
if ($availableSpace < 0) {
$query = \OC_DB::prepare('SELECT location,type,id,timestamp FROM *PREFIX*files_trash'
.' WHERE user=? ORDER BY timestamp ASC');
$query = \OC_DB::prepare('SELECT `location`,`type`,`id`,`timestamp` FROM `*PREFIX*files_trash`'
.' WHERE `user`=? ORDER BY `timestamp` ASC');
$result = $query->execute(array($user))->fetchAll();
$length = count($result);
$i = 0;
while ( $i < $length && $availableSpace < 0 ) {
$tmp = self::delete($result[$i]['id'], $result[$i]['timestamp']);
\OC_Log::write('files_trashbin', 'remove "'.$result[$i]['id'].'" ('.$tmp.'B) to meet the limit of trash bin size (50% of available quota)', \OC_log::INFO);
$availableSpace += $tmp;
$size += $tmp;
$i++;
@@ -490,7 +530,7 @@ class Trashbin {
* @return mixed trash bin size or false if no trash bin size is stored
*/
private static function getTrashbinSize($user) {
$query = \OC_DB::prepare('SELECT size FROM *PREFIX*files_trashsize WHERE user=?');
$query = \OC_DB::prepare('SELECT `size` FROM `*PREFIX*files_trashsize` WHERE `user`=?');
$result = $query->execute(array($user))->fetchAll();
if ($result) {
@@ -507,9 +547,9 @@ class Trashbin {
*/
private static function setTrashbinSize($user, $size) {
if ( self::getTrashbinSize($user) === false) {
$query = \OC_DB::prepare('INSERT INTO *PREFIX*files_trashsize (size, user) VALUES (?, ?)');
$query = \OC_DB::prepare('INSERT INTO `*PREFIX*files_trashsize` (`size`, `user`) VALUES (?, ?)');
}else {
$query = \OC_DB::prepare('UPDATE *PREFIX*files_trashsize SET size=? WHERE user=?');
$query = \OC_DB::prepare('UPDATE `*PREFIX*files_trashsize` SET `size`=? WHERE `user`=?');
}
$query->execute(array($size, $user));
}

View File

@@ -12,3 +12,5 @@ OCP\Util::connectHook('OC_Filesystem', 'write', "OCA\Files_Versions\Hooks", "wri
// Listen to delete and rename signals
OCP\Util::connectHook('OC_Filesystem', 'post_delete', "OCA\Files_Versions\Hooks", "remove_hook");
OCP\Util::connectHook('OC_Filesystem', 'rename', "OCA\Files_Versions\Hooks", "rename_hook");
//Listen to delete user signal
OCP\Util::connectHook('OC_User', 'pre_deleteUser', "OCA\Files_Versions\Hooks", "deleteUser_hook");

View File

@@ -6,7 +6,25 @@
<author>Frank Karlitschek</author>
<require>4.93</require>
<shipped>true</shipped>
<description>Versioning of files</description>
<description>
ownCloud supports simple version control for files. The versioning app
expires old versions automatically to make sure that
the user doesn't run out of space. Following pattern is used to delete
old versions:
For the first 10 seconds ownCloud keeps one version every 2 seconds;
For the first hour ownCloud keeps one version every minute;
For the first 24 hours ownCloud keeps one version every hour;
For the first 30 days ownCloud keeps one version every day;
After the first 30 days ownCloud keeps one version every week.
The versions are adjusted along this pattern every time a new version gets
created.
Beside that the version app takes care to never use more that 50% of the users
currently available free space. If the stored versions exceed this limit
ownCloud deletes the oldest versions until it meets the memory usage limit
again.
</description>
<types>
<filesystem/>
</types>

View File

@@ -63,4 +63,18 @@ class Hooks {
}
}
/**
* @brief clean up user specific settings if user gets deleted
* @param array with uid
*
* This function is connected to the pre_deleteUser signal of OC_Users
* to remove the used space for versions stored in the database
*/
public static function deleteUser_hook($params) {
if(\OCP\Config::getSystemValue('files_versions', Storage::DEFAULTENABLED)=='true') {
$uid = $params['uid'];
Storage::deleteUser($uid);
}
}
}

View File

@@ -53,7 +53,7 @@ class Storage {
* @return mixed versions size or false if no versions size is stored
*/
private static function getVersionsSize($user) {
$query = \OC_DB::prepare('SELECT size FROM *PREFIX*files_versions WHERE user=?');
$query = \OC_DB::prepare('SELECT `size` FROM `*PREFIX*files_versions` WHERE `user`=?');
$result = $query->execute(array($user))->fetchAll();
if ($result) {
@@ -70,9 +70,9 @@ class Storage {
*/
private static function setVersionsSize($user, $size) {
if ( self::getVersionsSize($user) === false) {
$query = \OC_DB::prepare('INSERT INTO *PREFIX*files_versions (size, user) VALUES (?, ?)');
$query = \OC_DB::prepare('INSERT INTO `*PREFIX*files_versions` (`size`, `user`) VALUES (?, ?)');
}else {
$query = \OC_DB::prepare('UPDATE *PREFIX*files_versions SET size=? WHERE user=?');
$query = \OC_DB::prepare('UPDATE `*PREFIX*files_versions` SET `size`=? WHERE `user`=?');
}
$query->execute(array($size, $user));
}
@@ -156,11 +156,18 @@ class Storage {
/**
* rename versions of a file
*/
public static function rename($oldpath, $newpath) {
list($uid, $oldpath) = self::getUidAndFilename($oldpath);
list($uidn, $newpath) = self::getUidAndFilename($newpath);
public static function rename($old_path, $new_path) {
list($uid, $oldpath) = self::getUidAndFilename($old_path);
list($uidn, $newpath) = self::getUidAndFilename($new_path);
$versions_view = new \OC\Files\View('/'.$uid .'/files_versions');
$files_view = new \OC\Files\View('/'.$uid .'/files');
// if the file already exists than it was a upload of a existing file
// over the web interface -> store() is the right function we need here
if ($files_view->file_exists($newpath)) {
return self::store($new_path);
}
$abs_newpath = $versions_view->getLocalFile($newpath);
if ( $files_view->is_dir($oldpath) && $versions_view->is_dir($oldpath) ) {
@@ -272,6 +279,18 @@ class Storage {
}
/**
* @brief deletes used space for files versions in db if user was deleted
*
* @param type $uid id of deleted user
* @return result of db delete operation
*/
public static function deleteUser($uid) {
$query = \OC_DB::prepare('DELETE FROM `*PREFIX*files_versions` WHERE `user`=?');
return $query->execute(array($uid));
}
/**
* @brief get the size of all stored versions from a given user
* @param $uid id from the user
@@ -359,12 +378,14 @@ class Storage {
$versions_fileview = new \OC\Files\View('/'.$uid.'/files_versions');
// get available disk space for user
$softQuota = true;
$quota = \OC_Preferences::getValue($uid, 'files', 'quota');
if ( $quota === null || $quota === 'default') {
$quota = \OC_Appconfig::getValue('files', 'default_quota');
}
if ( $quota === null || $quota === 'none' ) {
$quota = \OC\Files\Filesystem::free_space('/') / count(\OCP\User::getUsers());
$quota = \OC\Files\Filesystem::free_space('/');
$softQuota = false;
} else {
$quota = \OCP\Util::computerFileSize($quota);
}
@@ -378,15 +399,21 @@ class Storage {
}
// calculate available space for version history
$files_view = new \OC\Files\View('/'.$uid.'/files');
$rootInfo = $files_view->getFileInfo('/');
$free = $quota-$rootInfo['size']; // remaining free space for user
if ( $free > 0 ) {
$availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - $versionsSize; // how much space can be used for versions
// subtract size of files and current versions size from quota
if ($softQuota) {
$files_view = new \OC\Files\View('/'.$uid.'/files');
$rootInfo = $files_view->getFileInfo('/');
$free = $quota-$rootInfo['size']; // remaining free space for user
if ( $free > 0 ) {
$availableSpace = ($free * self::DEFAULTMAXSIZE / 100) - $versionsSize; // how much space can be used for versions
} else {
$availableSpace = $free-$versionsSize;
}
} else {
$availableSpace = $free-$versionsSize;
$availableSpace = $quota;
}
// after every 1000s run reduce the number of all versions not only for the current file
$random = rand(0, 1000);
if ($random == 0) {

View File

@@ -139,6 +139,9 @@ class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
if(!$this->enabled) {
return array();
}
if(!$this->groupExists($gid)) {
return array();
}
$cachekey = 'usersInGroup-'.$gid.'-'.$search.'-'.$limit.'-'.$offset;
// check for cache of the exact query
$groupUsers = $this->connection->getFromCache($cachekey);
@@ -178,7 +181,7 @@ class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
//we got uids, need to get their DNs to 'tranlsate' them to usernames
$filter = $this->combineFilterWithAnd(array(
\OCP\Util::mb_str_replace('%uid', $member,
$this->connection>ldapLoginFilter, 'UTF-8'),
$this->connection->ldapLoginFilter, 'UTF-8'),
$this->getFilterPartForUserSearch($search)
));
$ldap_users = $this->fetchListOfUsers($filter, 'dn');
@@ -214,6 +217,12 @@ class GROUP_LDAP extends lib\Access implements \OCP\GroupInterface {
* @returns array with display names (value) and user ids(key)
*/
public function displayNamesInGroup($gid, $search, $limit, $offset) {
if(!$this->enabled) {
return array();
}
if(!$this->groupExists($gid)) {
return array();
}
$users = $this->usersInGroup($gid, $search, $limit, $offset);
$displayNames = array();
foreach($users as $user) {

View File

@@ -62,7 +62,10 @@ abstract class Access {
$dn = $this->DNasBaseParameter($dn);
$rr = @ldap_read($cr, $dn, $filter, array($attr));
if(!is_resource($rr)) {
\OCP\Util::writeLog('user_ldap', 'readAttribute failed for DN '.$dn, \OCP\Util::DEBUG);
if(!empty($attr)) {
//do not throw this message on userExists check, irritates
\OCP\Util::writeLog('user_ldap', 'readAttribute failed for DN '.$dn, \OCP\Util::DEBUG);
}
//in case an error occurs , e.g. object does not exist
return false;
}
@@ -84,7 +87,7 @@ abstract class Access {
for($i=0;$i<$result[$attr]['count'];$i++) {
if($this->resemblesDN($attr)) {
$values[] = $this->sanitizeDN($result[$attr][$i]);
} elseif(strtolower($attr) == 'objectguid') {
} elseif(strtolower($attr) == 'objectguid' || strtolower($attr) == 'guid') {
$values[] = $this->convertObjectGUID2Str($result[$attr][$i]);
} else {
$values[] = $result[$attr][$i];
@@ -895,7 +898,7 @@ abstract class Access {
}
//for now, supported (known) attributes are entryUUID, nsuniqueid, objectGUID
$testAttributes = array('entryuuid', 'nsuniqueid', 'objectguid');
$testAttributes = array('entryuuid', 'nsuniqueid', 'objectguid', 'guid');
foreach($testAttributes as $attribute) {
\OCP\Util::writeLog('user_ldap', 'Testing '.$attribute.' as UUID attr', \OCP\Util::DEBUG);

View File

@@ -212,7 +212,6 @@ class Connection {
*/
private function readConfiguration($force = false) {
if((!$this->configured || $force) && !is_null($this->configID)) {
$defaults = $this->getDefaults();
$v = 'getValue';
$this->config['ldapHost'] = $this->$v('ldap_host');
$this->config['ldapBackupHost'] = $this->$v('ldap_backup_host');

View File

@@ -51,7 +51,8 @@ class Helper {
$query = '
SELECT DISTINCT `configkey`
FROM `*PREFIX*appconfig`
WHERE `configkey` LIKE ?
WHERE `appid` = \'user_ldap\'
AND `configkey` LIKE ?
';
if($activeConfigurations) {
$query .= ' AND `configvalue` = \'1\'';

View File

@@ -180,6 +180,11 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface {
* @return boolean
*/
public function getHome($uid) {
// user Exists check required as it is not done in user proxy!
if(!$this->userExists($uid)) {
return false;
}
$cacheKey = 'getHome'.$uid;
if($this->connection->isCached($cacheKey)) {
return $this->connection->getFromCache($cacheKey);
@@ -217,6 +222,10 @@ class USER_LDAP extends lib\Access implements \OCP\UserInterface {
* @return display name
*/
public function getDisplayName($uid) {
if(!$this->userExists($uid)) {
return false;
}
$cacheKey = 'getDisplayName'.$uid;
if(!is_null($displayName = $this->connection->getFromCache($cacheKey))) {
return $displayName;

View File

@@ -95,12 +95,12 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
// setup the email
$subject = (string)$l->t('User %s shared a file with you', $displayName);
if ($type === 'dir')
if ($type === 'folder')
$subject = (string)$l->t('User %s shared a folder with you', $displayName);
$text = (string)$l->t('User %s shared the file "%s" with you. It is available for download here: %s',
array($displayName, $file, $link));
if ($type === 'dir')
if ($type === 'folder')
$text = (string)$l->t('User %s shared the folder "%s" with you. It is available for download here: %s',
array($displayName, $file, $link));
@@ -110,7 +110,7 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
// send it out now
try {
OCP\Util::sendMail($to_address, $to_address, $subject, $text, $from_address, $user);
OCP\Util::sendMail($to_address, $to_address, $subject, $text, $from_address, $displayName);
OCP\JSON::success();
} catch (Exception $exception) {
OCP\JSON::error(array('data' => array('message' => OC_Util::sanitizeHTML($exception->getMessage()))));

View File

@@ -14,6 +14,10 @@ if (OC::checkUpgrade(false)) {
try {
$result = OC_DB::updateDbFromStructure(OC::$SERVERROOT.'/db_structure.xml');
$watcher->success('Updated database');
// do a file cache upgrade for users with files
// this can take loooooooooooooooooooooooong
__doFileCacheUpgrade($watcher);
} catch (Exception $exception) {
$watcher->failure($exception->getMessage());
}
@@ -26,6 +30,49 @@ if (OC::checkUpgrade(false)) {
$watcher->done();
}
/**
* The FileCache Upgrade routine
*
* @param UpdateWatcher $watcher
*/
function __doFileCacheUpgrade($watcher) {
try {
$query = \OC_DB::prepare('
SELECT DISTINCT `user`
FROM `*PREFIX*fscache`
');
$result = $query->execute();
} catch (\Exception $e) {
return;
}
$users = $result->fetchAll();
if(count($users) == 0) {
return;
}
$step = 100 / count($users);
$percentCompleted = 0;
$lastPercentCompletedOutput = 0;
$startInfoShown = false;
foreach($users as $userRow) {
$user = $userRow['user'];
\OC\Files\Filesystem::initMountPoints($user);
\OC\Files\Cache\Upgrade::doSilentUpgrade($user);
if(!$startInfoShown) {
//We show it only now, because otherwise Info about upgraded apps
//will appear between this and progress info
$watcher->success('Updating filecache, this may take really long...');
$startInfoShown = true;
}
$percentCompleted += $step;
$out = floor($percentCompleted);
if($out != $lastPercentCompletedOutput) {
$watcher->success('... '. $out.'% done ...');
$lastPercentCompletedOutput = $out;
}
}
$watcher->success('Updated filecache');
}
class UpdateWatcher {
/**
* @var \OC_EventSource $eventSource;

View File

@@ -12,7 +12,7 @@ table, td, th { vertical-align:middle; }
a { border:0; color:#000; text-decoration:none;}
a, a *, input, input *, select, .button span, li, label { cursor:pointer; }
ul { list-style:none; }
body { background:#fefefe; font:normal .8em/1.6em "Lucida Grande", Arial, Verdana, sans-serif; color:#000; }
body { background:#fefefe; font:normal .8em/1.6em "Helvetica Neue",Helvetica,Arial,FreeSans,sans-serif; color:#000; }
/* HEADERS */
@@ -40,7 +40,7 @@ filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#35537a', endC
input[type="text"], input[type="password"], input[type="search"], input[type="number"], input[type="email"],
textarea, select, button, .button, #quota, div.jp-progress, .pager li a {
width:10em; margin:.3em; padding:.6em .5em .4em;
font-size:1em; font-family:Arial, Verdana, sans-serif;
font-size:1em;
background:#fff; color:#333; border:1px solid #ddd; outline:none;
-moz-box-shadow:0 1px 1px #fff, 0 2px 0 #bbb inset; -webkit-box-shadow:0 1px 1px #fff, 0 1px 0 #bbb inset; box-shadow:0 1px 1px #fff, 0 1px 0 #bbb inset;
-moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em;
@@ -80,12 +80,27 @@ input[type="submit"], input[type="button"], button, .button, #quota, div.jp-prog
-moz-box-shadow:0 1px 1px rgba(255,255,255,.9), 0 1px 1px rgba(255,255,255,.9) inset; -webkit-box-shadow:0 1px 1px rgba(255,255,255,.9), 0 1px 1px rgba(255,255,255,.9) inset; box-shadow:0 1px 1px rgba(255,255,255,.9), 0 1px 1px rgba(255,255,255,.9) inset;
-moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em;
}
input[type="submit"]:hover, input[type="submit"]:focus, input[type="button"]:hover, select:hover, select:focus, select:active, input[type="button"]:focus, .button:hover {
background:rgba(250,250,250,.9); color:#333;
input[type="submit"]:hover, input[type="submit"]:focus,
input[type="button"]:hover, input[type="button"]:focus,
button:hover, button:focus,
.button:hover, .button:focus,
select:hover, select:focus, select:active {
background-color:rgba(250,250,250,.9);
color:#333;
}
input[type="submit"] img, input[type="button"] img, button img, .button img { cursor:pointer; }
#header .button { border:none; -moz-box-shadow:none; -webkit-box-shadow:none; box-shadow:none; }
/* disabled input fields and buttons */
input:disabled, input:disabled:hover, input:disabled:focus,
button:disabled, button:disabled:hover, button:disabled:focus,
.button:disabled, .button:disabled:hover, .button:disabled:focus,
a.disabled, a.disabled:hover, a.disabled:focus {
background: rgba(230,230,230,.9);
color: #999;
cursor: default;
}
/* Primary action button, use sparingly */
.primary, input[type="submit"].primary, input[type="button"].primary, button.primary, .button.primary {
border:1px solid #1d2d44;
@@ -242,22 +257,48 @@ fieldset.warning a { color:#b94a48 !important; font-weight:bold; }
/* NAVIGATION ------------------------------------------------------------- */
#navigation {
position:fixed; top:3.5em; float:left; width:64px; padding:0; z-index:75; height:100%;
position:fixed; float:left; width:64px; padding-top:3.5em; z-index:75; height:100%;
background:#383c43 url('../img/noise.png') repeat; border-right:1px #333 solid;
-moz-box-shadow:0 0 7px #000; -webkit-box-shadow:0 0 7px #000; box-shadow:0 0 7px #000;
overflow:hidden;
overflow:hidden; box-sizing:border-box; -moz-box-sizing:border-box;
}
#navigation:hover { overflow-y:auto; }
#navigation a {
display:block; padding:8px 0 4px;
#navigation:hover { overflow-y:auto; } /* show scrollbar only on hover */
#navigation a span {
display:block;
text-decoration:none; font-size:10px; text-align:center;
color:#fff; text-shadow:#000 0 -1px 0;
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; filter:alpha(opacity=50); opacity:.5;
white-space:nowrap; overflow:hidden; text-overflow:ellipsis; // ellipsize long app names
white-space:nowrap; overflow:hidden; text-overflow:ellipsis; /* ellipsize long app names */
}
#navigation a:hover, #navigation a:focus { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=80)"; filter:alpha(opacity=80); opacity:.8; }
#navigation a.active { -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)"; filter:alpha(opacity=100); opacity:1; }
#navigation .icon { display:block; width:32px; height:32px; margin:0 16px 0; }
/* icon opacity and hover effect */
#navigation a img,
#navigation a span {
/* 50% opacity when inactive */
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
filter: alpha(opacity=50);
opacity: .5;
}
#navigation a:hover img, #navigation a:focus img,
#navigation a:hover span, #navigation a:focus span {
/* 80% opacity when hovered or focused */
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
filter: alpha(opacity=80);
opacity: .8;
}
#navigation a.active img,
#navigation a.active span {
/* full opacity for the active app */
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
filter: alpha(opacity=100);
opacity: 1;
}
/* positioning */
#navigation .icon {
display:block;
width:32px; height:32px;
margin:0 16px 0; padding:8px 0 4px;
}
#navigation li:first-child a { padding-top:16px; }
@@ -360,3 +401,212 @@ div.crumb { float:left; display:block; background:url('../img/breadcrumb.svg') n
div.crumb:first-child { padding:10px 20px 10px 5px; }
div.crumb.last { font-weight:bold; background:none; padding-right:10px; }
div.crumb a{ padding: 0.9em 0 0.7em 0; }
/* ---- APP STYLING ---- */
#app {
height: 100%;
width: 100%;
}
/* Navigation: folder like structure */
#app-navigation {
width: 250px;
height: 100%;
float: left;
padding-bottom: 32px;
-moz-box-sizing: border-box; box-sizing: border-box;
background-color: #f8f8f8;
border-right: 1px solid #ccc;
}
#app-navigation > ul {
height: 100%;
overflow: auto;
-moz-box-sizing: border-box; box-sizing: border-box;
}
#app-navigation li {
position: relative;
width: 100%;
-moz-box-sizing: border-box; box-sizing: border-box;
text-shadow: 0 1px 0 rgba(255,255,255,.9);
}
#app-navigation .active,
#app-navigation .active a { /* active navigation entry or folder */
background-color: #ddd;
text-shadow: 0 1px 0 rgba(255,255,255,.7);
}
/* special rules for first-level entries and folders */
#app-navigation > ul > li {
background-color: #eee;
border-top: 1px solid #fff;
border-bottom: 1px solid #ddd;
}
#app-navigation > ul > .active {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
}
#app-navigation .with-icon a {
padding-left: 32px;
background-size: 16px 16px; background-position: 10px center; background-repeat: no-repeat;
}
#app-navigation li > a {
display: block;
width: 100%;
padding: 0 16px;
overflow: hidden;
-moz-box-sizing: border-box; box-sizing: border-box;
line-height: 32px;
white-space: nowrap;
text-overflow: ellipsis;
color: #333;
}
#app-navigation li:hover > a {
background-color: #ddd;
}
#app-navigation > ul > li:hover {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
}
#app-navigation .collapse {
display: none; /* hide collapse button intially */
}
#app-navigation .collapsible > .collapse {
position: absolute;
left: 6px;
top: 5px;
height: 16px;
width: 16px;
background: none; background-image: url('../img/actions/triangle-s.svg');
background-size: 16px 16px; background-repeat: no-repeat;
border: none;
border-radius: 0;
outline: none !important;
box-shadow: none;
}
#app-navigation .collapsible:hover > a {
background-image: none;
}
#app-navigation .collapsible:hover > .collapse {
display: block;
}
#app-navigation .collapsible .collapse {
-moz-transform: rotate(-90deg);
-webkit-transform: rotate(-90deg);
-ms-transform:rotate(-90deg);
-o-transform:rotate(-90deg);
transform: rotate(-90deg);
}
#app-navigation .collapsible.open .collapse {
-moz-transform: rotate(0);
-webkit-transform: rotate(0);
-ms-transform:rotate(0);
-o-transform:rotate(0);
transform: rotate(0);
}
/* Second level nesting for lists */
#app-navigation > ul ul {
display: none;
}
#app-navigation > ul ul li > a {
padding-left: 32px;
}
#app-navigation > .with-icon ul li > a {
padding-left: 48px;
background-position: 24px center;
}
#app-navigation .open {
background-image: linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%);
background-image: -o-linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%);
background-image: -moz-linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%);
background-image: -webkit-linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%);
background-image: -ms-linear-gradient(top, rgb(238,238,238) 0%, rgb(245,245,245) 100%);
}
#app-navigation > ul .open:hover {
-moz-box-shadow: inset 0 0 3px #ccc; -webkit-box-shadow: inset 0 0 3px #ccc; box-shadow: inset 0 0 3px #ccc;
border-top: 1px solid #ccc;
}
#app-navigation > ul .open ul {
display: block;
}
/* drag and drop */
#app-navigation .drag-and-drop {
-moz-transition: padding-bottom 500ms ease 0s;
-o-transition: padding-bottom 500ms ease 0s;
-webkit-transition: padding-bottom 500ms ease 0s;
-ms-transition: padding-bottom 500ms ease 0s;
transition: padding-bottom 500ms ease 0s;
padding-bottom: 40px;
}
#app-navigation .personalblock > legend { /* TODO @Raydiation: still needed? */
padding: 10px 0; margin: 0;
}
#app-navigation .error {
color: #dd1144;
}
/* Part where the content will be loaded into */
#app-content {
height: 100%;
overflow-y: auto;
}
/* settings area */
#app-settings {
position: fixed;
width: 249px;
bottom: 0;
border-top: 1px solid #ccc;
}
#app-settings-header {
background-color: #eee;
}
#app-settings-content {
display: none;
padding: 10px;
background-color: #eee;
}
#app-settings.open #app-settings-content {
display: block;
}
.settings-button {
display: block;
height: 32px;
width: 100%;
padding: 0;
margin: 0;
background-color: transparent; background-image: url('../img/actions/settings.svg');
background-position: 10px center; background-repeat: no-repeat;
box-shadow: none;
border: 0;
border-radius: 0;
}
.settings-button:hover {
background-color: #ddd;
}
/* icons */
.folder-icon { background-image: url('../img/places/folder.svg'); }
.delete-icon { background-image: url('../img/actions/delete.svg'); }
.delete-icon:hover { background-image: url('../img/actions/delete-hover.svg'); }
.edit-icon { background-image: url('../img/actions/rename.svg'); }
/* buttons */
button.loading {
background-image: url('../img/loading.gif');
background-position: right 10px center; background-repeat: no-repeat;
padding-right: 30px;
}

View File

@@ -133,14 +133,14 @@ OC.Share={
callback();
}
} else {
OC.dialogs.alert(t('core', 'Error'), t('core', 'Error while unsharing'));
OC.dialogs.alert(t('core', 'Error while unsharing'), t('core', 'Error'));
}
});
},
setPermissions:function(itemType, itemSource, shareType, shareWith, permissions) {
$.post(OC.filePath('core', 'ajax', 'share.php'), { action: 'setPermissions', itemType: itemType, itemSource: itemSource, shareType: shareType, shareWith: shareWith, permissions: permissions }, function(result) {
if (!result || result.status !== 'success') {
OC.dialogs.alert(t('core', 'Error'), t('core', 'Error while changing permissions'));
OC.dialogs.alert(t('core', 'Error while changing permissions'), t('core', 'Error'));
}
});
},
@@ -271,7 +271,7 @@ OC.Share={
}
var collectionList = $('#shareWithList li').filterAttr('data-collection', item);
if (collectionList.length > 0) {
$(collectionList).append(', '+shareWith);
$(collectionList).append(', '+shareWithDisplayName);
} else {
var html = '<li style="clear: both;" data-collection="'+item+'">'+t('core', 'Shared in {item} with {user}', {'item': item, user: shareWithDisplayName})+'</li>';
$('#shareWithList').prepend(html);
@@ -383,7 +383,7 @@ OC.Share={
}
$(document).ready(function() {
if(typeof monthNames != 'undefined'){
$.datepicker.setDefaults({
monthNames: monthNames,
@@ -421,7 +421,7 @@ $(document).ready(function() {
$(this).click(function(event) {
var target = $(event.target);
var isMatched = !target.is('.drop, .ui-datepicker-next, .ui-datepicker-prev, .ui-icon')
var isMatched = !target.is('.drop, .ui-datepicker-next, .ui-datepicker-prev, .ui-icon')
&& !target.closest('#ui-datepicker-div').length;
if (OC.Share.droppedDown && isMatched && $('#dropdown').has(event.target).length === 0) {
OC.Share.hideDropDown();
@@ -563,19 +563,19 @@ $(document).ready(function() {
var itemSource = $('#dropdown').data('item-source');
$.post(OC.filePath('core', 'ajax', 'share.php'), { action: 'setExpirationDate', itemType: itemType, itemSource: itemSource, date: '' }, function(result) {
if (!result || result.status !== 'success') {
OC.dialogs.alert(t('core', 'Error'), t('core', 'Error unsetting expiration date'));
OC.dialogs.alert(t('core', 'Error unsetting expiration date'), t('core', 'Error'));
}
$('#expirationDate').hide();
});
}
});
$(document).on('change', '#dropdown #expirationDate', function() {
var itemType = $('#dropdown').data('item-type');
var itemSource = $('#dropdown').data('item-source');
$.post(OC.filePath('core', 'ajax', 'share.php'), { action: 'setExpirationDate', itemType: itemType, itemSource: itemSource, date: $(this).val() }, function(result) {
if (!result || result.status !== 'success') {
OC.dialogs.alert(t('core', 'Error'), t('core', 'Error setting expiration date'));
OC.dialogs.alert(t('core', 'Error setting expiration date'), t('core', 'Error'));
}
});
});

View File

@@ -18,6 +18,10 @@ $hasPostgreSQL = is_callable('pg_connect');
$hasOracle = is_callable('oci_connect');
$hasMSSQL = is_callable('sqlsrv_connect');
$datadir = OC_Config::getValue('datadirectory', OC::$SERVERROOT.'/data');
$vulnerableToNullByte = false;
if(@file_exists(__FILE__."\0Nullbyte")) { // Check if the used PHP version is vulnerable to the NULL Byte attack (CVE-2006-7243)
$vulnerableToNullByte = true;
}
// Protect data directory here, so we can test if the protection is working
OC_Setup::protectDataDirectory();
@@ -31,6 +35,7 @@ $opts = array(
'directory' => $datadir,
'secureRNG' => OC_Util::secureRNG_available(),
'htaccessWorking' => OC_Util::ishtaccessworking(),
'vulnerableToNullByte' => $vulnerableToNullByte,
'errors' => array(),
);

View File

@@ -19,6 +19,13 @@
<?php endforeach; ?>
</ul>
<?php endif; ?>
<?php if($_['vulnerableToNullByte']): ?>
<fieldset class="warning">
<legend><strong><?php p($l->t('Security Warning'));?></strong></legend>
<p><?php p($l->t('Your PHP version is vulnerable to the NULL Byte attack (CVE-2006-7243)'));?><br/>
<?php p($l->t('Please update your PHP installation to use ownCloud securely.'));?></p>
</fieldset>
<?php endif; ?>
<?php if(!$_['secureRNG']): ?>
<fieldset class="warning">
<legend><strong><?php p($l->t('Security Warning'));?></strong></legend>

View File

@@ -75,7 +75,9 @@
<a href="<?php print_unescaped($entry['href']); ?>" title=""
<?php if( $entry['active'] ): ?> class="active"<?php endif; ?>>
<img class="icon svg" src="<?php print_unescaped($entry['icon']); ?>"/>
<?php p($entry['name']); ?>
<span>
<?php p($entry['name']); ?>
</span>
</a>
</li>
<?php endforeach; ?>

View File

@@ -48,6 +48,8 @@ function handleUnexpectedShutdown() {
$RUNTIME_NOSETUPFS = true;
require_once 'lib/base.php';
session_write_close();
// Don't do anything if ownCloud has not been installed
if( !OC_Config::getValue( 'installed', false )) {
exit( 0 );

View File

@@ -651,6 +651,14 @@
<length>255</length>
</field>
<index>
<name>property_index</name>
<field>
<name>userid</name>
<sorting>ascending</sorting>
</field>
</index>
</declaration>
</table>
@@ -859,7 +867,6 @@
<name>displayname</name>
<type>text</type>
<default></default>
<notnull>true</notnull>
<length>64</length>
</field>

View File

@@ -851,7 +851,11 @@ class OC_App{
foreach($apps as $app) {
// check if the app is compatible with this version of ownCloud
$info = OC_App::getAppInfo($app);
if(!isset($info['require']) or !self::isAppVersionCompatible($version, $info['require'])) {
if(!isset($info['require'])
or !self::isAppVersionCompatible($version, $info['require'])
// manually disable files_archive app since it has been removed
// and cause update problems
or $app === 'files_archive') {
OC_Log::write('core',
'App "'.$info['name'].'" ('.$app.') can\'t be used because it is'
.' not compatible with this version of ownCloud',

View File

@@ -78,6 +78,8 @@ class OC {
* SPL autoload
*/
public static function autoload($className) {
$className = trim($className, '\\');
if (array_key_exists($className, OC::$CLASSPATH)) {
$path = OC::$CLASSPATH[$className];
/** @TODO: Remove this when necessary
@@ -276,7 +278,7 @@ class OC {
OC_Config::setValue('maintenance', true);
OC_Log::write('core',
'starting upgrade from ' . $installedVersion . ' to ' . $currentVersion,
OC_Log::DEBUG);
OC_Log::WARN);
$minimizerCSS = new OC_Minimizer_CSS();
$minimizerCSS->clearCache();
$minimizerJS = new OC_Minimizer_JS();
@@ -398,8 +400,8 @@ class OC {
ini_set('arg_separator.output', '&amp;');
// try to switch magic quotes off.
if (get_magic_quotes_gpc()) {
@set_magic_quotes_runtime(false);
if (get_magic_quotes_gpc()==1) {
ini_set('magic_quotes_runtime', 0);
}
//try to configure php to enable big file uploads.

View File

@@ -292,8 +292,10 @@ class OC_DB {
'username' => $user,
'password' => $pass,
'hostspec' => $host,
'database' => $name
);
'database' => $name,
'charset' => 'UTF-8'
);
$options['portability'] = $options['portability'] - MDB2_PORTABILITY_EMPTY_TO_NULL;
break;
default:
return false;

View File

@@ -50,7 +50,7 @@ class OC_Files {
$xsendfile = true;
}
if (count($files) == 1) {
if (is_array($files) && count($files) == 1) {
$files = $files[0];
}

View File

@@ -203,7 +203,10 @@ class Cache {
$query = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache`(' . implode(', ', $queryParts) . ')'
. ' VALUES(' . implode(', ', $valuesPlaceholder) . ')');
$query->execute($params);
$result = $query->execute($params);
if (\OC_DB::isError($result)) {
\OCP\Util::writeLog('cache', 'Insert to cache failed: '.$result, \OCP\Util::ERROR);
}
return (int)\OC_DB::insertid('*PREFIX*filecache');
}
@@ -340,9 +343,9 @@ class Cache {
$query->execute(array($targetPath, md5($targetPath), $child['fileid']));
}
$query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ?, `parent` =?'
$query = \OC_DB::prepare('UPDATE `*PREFIX*filecache` SET `path` = ?, `path_hash` = ?, `name` = ?, `parent` =?'
. ' WHERE `fileid` = ?');
$query->execute(array($target, md5($target), $newParentId, $sourceId));
$query->execute(array($target, md5($target), basename($target), $newParentId, $sourceId));
}
/**

View File

@@ -72,7 +72,44 @@ class Legacy {
$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*fscache` WHERE `path` = ?');
}
$result = $query->execute(array($path));
return $result->fetchRow();
$data = $result->fetchRow();
$data['etag'] = $this->getEtag($data['path'], $data['user']);
return $data;
}
/**
* Get the ETag for the given path
*
* @param type $path
* @return string
*/
function getEtag($path, $user = null) {
static $query = null;
$pathDetails = explode('/', $path, 4);
if((!$user) && !isset($pathDetails[1])) {
//no user!? Too odd, return empty string.
return '';
} else if(!$user) {
//guess user from path, if no user passed.
$user = $pathDetails[1];
}
if(!isset($pathDetails[3]) || is_null($pathDetails[3])) {
$relativePath = '';
} else {
$relativePath = $pathDetails[3];
}
if(is_null($query)){
$query = \OC_DB::prepare('SELECT `propertyvalue` FROM `*PREFIX*properties` WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = \'{DAV:}getetag\'');
}
$result = $query->execute(array($user, '/' . $relativePath));
if ($row = $result->fetchRow()) {
return trim($row['propertyvalue'], '"');
} else {
return '';
}
}
/**
@@ -82,6 +119,10 @@ class Legacy {
function getChildren($id) {
$query = \OC_DB::prepare('SELECT * FROM `*PREFIX*fscache` WHERE `parent` = ?');
$result = $query->execute(array($id));
return $result->fetchAll();
$data = $result->fetchAll();
foreach ($data as $i => $item) {
$data[$i]['etag'] = $this->getEtag($item['path'], $item['user']);
}
return $data;
}
}

View File

@@ -62,36 +62,42 @@ class Scanner {
* @return array with metadata of the scanned file
*/
public function scanFile($file, $checkExisting = false) {
\OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', array('path' => $file, 'storage' => $this->storageId));
$data = $this->getData($file);
if ($data) {
if ($file) {
$parent = dirname($file);
if ($parent === '.') {
$parent = '';
if (!self::isIgnoredFile($file)) {
\OC_Hook::emit('\OC\Files\Cache\Scanner', 'scan_file', array('path' => $file, 'storage' => $this->storageId));
$data = $this->getData($file);
if ($data) {
if ($file) {
$parent = dirname($file);
if ($parent === '.') {
$parent = '';
}
if (!$this->cache->inCache($parent)) {
$this->scanFile($parent);
}
}
if (!$this->cache->inCache($parent)) {
$this->scanFile($parent);
if($cacheData = $this->cache->get($file)) {
if ($data['mtime'] === $cacheData['mtime'] &&
$data['size'] === $cacheData['size']) {
$data['etag'] = $cacheData['etag'];
}
}
if ($checkExisting and $cacheData) {
if ($data['size'] === -1) {
$data['size'] = $cacheData['size'];
}
}
$this->cache->put($file, $data);
}
if ($checkExisting and $cacheData = $this->cache->get($file)) {
if ($data['size'] === -1) {
$data['size'] = $cacheData['size'];
}
if ($data['mtime'] === $cacheData['mtime']) {
$data['etag'] = $cacheData['etag'];
}
}
$this->cache->put($file, $data);
return $data;
}
return $data;
return null;
}
/**
* scan all the files in a folder and store them in the cache
*
* @param string $path
* @param SCAN_RECURSIVE/SCAN_SHALLOW $recursive
* @param bool $recursive
* @param bool $onlyChilds
* @return int the size of the scanned folder or -1 if the size is unknown at this stage
*/
@@ -106,7 +112,7 @@ class Scanner {
if ($this->storage->is_dir($path) && ($dh = $this->storage->opendir($path))) {
\OC_DB::beginTransaction();
while ($file = readdir($dh)) {
if (!$this->isIgnoredFile($file)) {
if (!$this->isIgnoredDir($file)) {
$child = ($path) ? $path . '/' . $file : $file;
$data = $this->scanFile($child, $recursive === self::SCAN_SHALLOW);
if ($data) {
@@ -141,6 +147,18 @@ class Scanner {
return $size;
}
/**
* @brief check if the directory should be ignored when scanning
* NOTE: the special directories . and .. would cause never ending recursion
* @param String $dir
* @return boolean
*/
private function isIgnoredDir($dir) {
if ($dir === '.' || $dir === '..') {
return true;
}
return false;
}
/**
* @brief check if the file should be ignored when scanning
* NOTE: files with a '.part' extension are ignored as well!
@@ -148,9 +166,9 @@ class Scanner {
* @param String $file
* @return boolean
*/
private function isIgnoredFile($file) {
if ($file === '.' || $file === '..'
|| pathinfo($file, PATHINFO_EXTENSION) === 'part'
public static function isIgnoredFile($file) {
if (pathinfo($file, PATHINFO_EXTENSION) === 'part'
|| \OC\Files\Filesystem::isFileBlacklisted($file)
) {
return true;
}

View File

@@ -53,12 +53,36 @@ class Updater {
}
}
static public function renameUpdate($from, $to) {
/**
* @var \OC\Files\Storage\Storage $storageFrom
* @var \OC\Files\Storage\Storage $storageTo
* @var string $internalFrom
* @var string $internalTo
*/
list($storageFrom, $internalFrom) = self::resolvePath($from);
list($storageTo, $internalTo) = self::resolvePath($to);
if ($storageFrom && $storageTo) {
if ($storageFrom === $storageTo) {
$cache = $storageFrom->getCache($internalFrom);
$cache->move($internalFrom, $internalTo);
$cache->correctFolderSize($internalFrom);
$cache->correctFolderSize($internalTo);
self::correctFolder($from, time());
self::correctFolder($to, time());
} else {
self::deleteUpdate($from);
self::writeUpdate($to);
}
}
}
/**
* Update the mtime and ETag of all parent folders
*
* @param string $path
* @param string $time
*/
* Update the mtime and ETag of all parent folders
*
* @param string $path
* @param string $time
*/
static public function correctFolder($path, $time) {
if ($path !== '' && $path !== '/') {
$parent = dirname($path);
@@ -66,9 +90,9 @@ class Updater {
$parent = '';
}
/**
* @var \OC\Files\Storage\Storage $storage
* @var string $internalPath
*/
* @var \OC\Files\Storage\Storage $storage
* @var string $internalPath
*/
list($storage, $internalPath) = self::resolvePath($parent);
if ($storage) {
$cache = $storage->getCache();
@@ -88,12 +112,18 @@ class Updater {
self::writeUpdate($params['path']);
}
/**
* @param array $params
*/
static public function touchHook($params) {
self::writeUpdate($params['path']);
}
/**
* @param array $params
*/
static public function renameHook($params) {
self::deleteUpdate($params['oldpath']);
self::writeUpdate($params['newpath']);
self::renameUpdate($params['oldpath'], $params['newpath']);
}
/**

View File

@@ -36,12 +36,12 @@ class Upgrade {
return;
}
\OC_Hook::emit('\OC\Files\Cache\Upgrade', 'migrate_path', $path);
if ($row = $this->legacy->get($path)) {
$data = $this->getNewData($row);
$this->insert($data);
$this->upgradeChilds($data['id'], $mode);
if ($data) {
$this->insert($data);
$this->upgradeChilds($data['id'], $mode);
}
}
}
@@ -53,9 +53,11 @@ class Upgrade {
foreach ($children as $child) {
$childData = $this->getNewData($child);
\OC_Hook::emit('\OC\Files\Cache\Upgrade', 'migrate_path', $child['path']);
$this->insert($childData);
if ($mode == Scanner::SCAN_RECURSIVE) {
$this->upgradeChilds($child['id']);
if ($childData) {
$this->insert($childData);
if ($mode == Scanner::SCAN_RECURSIVE) {
$this->upgradeChilds($child['id']);
}
}
}
}
@@ -64,14 +66,16 @@ class Upgrade {
* @param array $data the data for the new cache
*/
function insert($data) {
if (!$this->inCache($data['storage'], $data['path_hash'], $data['id'])) {
static $insertQuery = null;
if(is_null($insertQuery)) {
$insertQuery = \OC_DB::prepare('INSERT INTO `*PREFIX*filecache`
( `fileid`, `storage`, `path`, `path_hash`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted` )
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
( `fileid`, `storage`, `path`, `path_hash`, `parent`, `name`, `mimetype`, `mimepart`, `size`, `mtime`, `encrypted`, `etag` )
VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
}
if (!$this->inCache($data['storage'], $data['path_hash'], $data['id'])) {
$insertQuery->execute(array($data['id'], $data['storage'],
$data['path'], $data['path_hash'], $data['parent'], $data['name'],
$data['mimetype'], $data['mimepart'], $data['size'], $data['mtime'], $data['encrypted']));
$data['mimetype'], $data['mimepart'], $data['size'], $data['mtime'], $data['encrypted'], $data['etag']));
}
}
@@ -82,7 +86,10 @@ class Upgrade {
* @return bool
*/
function inCache($storage, $pathHash, $id) {
$query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE (`storage` = ? AND `path_hash` = ?) OR `fileid` = ?');
static $query = null;
if(is_null($query)) {
$query = \OC_DB::prepare('SELECT `fileid` FROM `*PREFIX*filecache` WHERE (`storage` = ? AND `path_hash` = ?) OR `fileid` = ?');
}
$result = $query->execute(array($storage, $pathHash, $id));
return (bool)$result->fetchRow();
}
@@ -91,24 +98,53 @@ class Upgrade {
* get the new data array from the old one
*
* @param array $data the data from the old cache
* Example data array
* Array
* (
* [id] => 418
* [path] => /tina/files/picture.jpg //relative to datadir
* [path_hash] => 66d4547e372888deed80b24fec9b192b
* [parent] => 234
* [name] => picture.jpg
* [user] => tina
* [size] => 1265283
* [ctime] => 1363909709
* [mtime] => 1363909709
* [mimetype] => image/jpeg
* [mimepart] => image
* [encrypted] => 0
* [versioned] => 0
* [writable] => 1
* )
*
* @return array
*/
function getNewData($data) {
//Make sure there is a path, otherwise we can do nothing.
if(!isset($data['path'])) {
return false;
}
$newData = $data;
list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($data['path']);
/**
* @var \OC\Files\Storage\Storage $storage
* @var string $internalPath;
*/
$newData['path_hash'] = md5($internalPath);
$newData['path'] = $internalPath;
$newData['storage'] = $this->getNumericId($storage);
$newData['parent'] = ($internalPath === '') ? -1 : $data['parent'];
$newData['permissions'] = ($data['writable']) ? \OCP\PERMISSION_ALL : \OCP\PERMISSION_READ;
$newData['storage_object'] = $storage;
$newData['mimetype'] = $this->getMimetypeId($newData['mimetype'], $storage);
$newData['mimepart'] = $this->getMimetypeId($newData['mimepart'], $storage);
return $newData;
list($storage, $internalPath) = \OC\Files\Filesystem::resolvePath($data['path']);
if ($storage) {
$newData['etag'] = $data['etag'];
$newData['path_hash'] = md5($internalPath);
$newData['path'] = $internalPath;
$newData['storage'] = $this->getNumericId($storage);
$newData['parent'] = ($internalPath === '') ? -1 : $data['parent'];
$newData['permissions'] = ($data['writable']) ? \OCP\PERMISSION_ALL : \OCP\PERMISSION_READ;
$newData['storage_object'] = $storage;
$newData['mimetype'] = $this->getMimetypeId($newData['mimetype'], $storage);
$newData['mimepart'] = $this->getMimetypeId($newData['mimepart'], $storage);
return $newData;
} else {
\OC_Log::write('core', 'Unable to migrate data from old cache for '.$data['path'].' because the storage was not found', \OC_Log::ERROR);
return false;
}
}
/**
@@ -158,4 +194,25 @@ class Upgrade {
static function upgradeDone($user) {
\OCP\Config::setUserValue($user, 'files', 'cache_version', 5);
}
/**
* Does a "silent" upgrade, i.e. without an Event-Source as triggered
* on User-Login via Ajax. This method is called within the regular
* ownCloud upgrade.
*
* @param string $user a User ID
*/
public static function doSilentUpgrade($user) {
if(!self::needUpgrade($user)) {
return;
}
$legacy = new \OC\Files\Cache\Legacy($user);
if ($legacy->hasItems()) {
\OC_DB::beginTransaction();
$upgrade = new \OC\Files\Cache\Upgrade($legacy);
$upgrade->upgradePath('/' . $user . '/files');
\OC_DB::commit();
}
\OC\Files\Cache\Upgrade::upgradeDone($user);
}
}

View File

@@ -23,6 +23,7 @@
* post_rename(oldpath,newpath)
* copy(oldpath,newpath, &run) (if the newpath doesn't exists yes, copy, create and write will be emitted in that order)
* post_rename(oldpath,newpath)
* post_initMountPoints(user, user_dir)
*
* the &run parameter can be set to false to prevent the operation from occurring
*/
@@ -279,6 +280,9 @@ class Filesystem {
}
}
}
// Chance to mount for other storages
\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', array('user' => $user, 'user_dir' => $root));
}
/**
@@ -659,8 +663,4 @@ class Filesystem {
}
}
\OC_Hook::connect('OC_Filesystem', 'post_write', '\OC\Files\Cache\Updater', 'writeHook');
\OC_Hook::connect('OC_Filesystem', 'post_delete', '\OC\Files\Cache\Updater', 'deleteHook');
\OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Updater', 'renameHook');
\OC_Util::setupFS();

View File

@@ -77,7 +77,9 @@ class Mapper
$result = $query->execute(array($path1.'%'));
$updateQuery = \OC_DB::prepare('UPDATE `*PREFIX*file_map`'
.' SET `logic_path` = ?'
.' AND `physic_path` = ?'
.' , `logic_path_hash` = ?'
.' , `physic_path` = ?'
.' , `physic_path_hash` = ?'
.' WHERE `logic_path` = ?');
while( $row = $result->fetchRow()) {
$currentLogic = $row['logic_path'];
@@ -86,7 +88,7 @@ class Mapper
$newPhysic = $physicPath2.$this->stripRootFolder($currentPhysic, $physicPath1);
if ($path1 !== $currentLogic) {
try {
$updateQuery->execute(array($newLogic, $newPhysic, $currentLogic));
$updateQuery->execute(array($newLogic, md5($newLogic), $newPhysic, md5($newPhysic), $currentLogic));
} catch (\Exception $e) {
error_log('Mapper::Copy failed '.$currentLogic.' -> '.$newLogic.'\n'.$e);
throw $e;
@@ -149,7 +151,7 @@ class Mapper
// detect duplicates
while ($this->resolvePhysicalPath($physicalPath) !== null) {
$physicalPath = $this->slugifyPath($physicalPath, $index++);
$physicalPath = $this->slugifyPath($logicPath, $index++);
}
// insert the new path mapping if requested
@@ -165,32 +167,41 @@ class Mapper
$query->execute(array($logicPath, $physicalPath, md5($logicPath), md5($physicalPath)));
}
private function slugifyPath($path, $index=null) {
public function slugifyPath($path, $index=null) {
$path = $this->stripRootFolder($path, $this->unchangedPhysicalRoot);
$pathElements = explode('/', $path);
$sluggedElements = array();
// rip off the extension ext from last element
$last= end($pathElements);
$parts = pathinfo($last);
$filename = $parts['filename'];
array_pop($pathElements);
array_push($pathElements, $filename);
foreach ($pathElements as $pathElement) {
// remove empty elements
if (empty($pathElement)) {
continue;
}
// TODO: remove file ext before slugify on last element
$sluggedElements[] = self::slugify($pathElement);
}
//
// TODO: add the index before the file extension
//
// apply index to file name
if ($index !== null) {
$last= end($sluggedElements);
array_pop($sluggedElements);
$last= array_pop($sluggedElements);
array_push($sluggedElements, $last.'-'.$index);
}
$sluggedPath = $this->unchangedPhysicalRoot.implode(DIRECTORY_SEPARATOR, $sluggedElements);
// add back the extension
if (isset($parts['extension'])) {
$last= array_pop($sluggedElements);
array_push($sluggedElements, $last.'.'.$parts['extension']);
}
$sluggedPath = $this->unchangedPhysicalRoot.implode('/', $sluggedElements);
return $this->stripLast($sluggedPath);
}
@@ -210,7 +221,7 @@ class Mapper
// transliterate
if (function_exists('iconv')) {
$text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
$text = iconv('utf-8', 'us-ascii//TRANSLIT//IGNORE', $text);
}
// lowercase
@@ -219,10 +230,8 @@ class Mapper
// remove unwanted characters
$text = preg_replace('~[^-\w]+~', '', $text);
if (empty($text))
{
// TODO: we better generate a guid in this case
return 'n-a';
if (empty($text)) {
return uniqid();
}
return $text;

View File

@@ -90,7 +90,11 @@ class Mount {
public function getStorageId() {
if (!$this->storageId) {
if (is_null($this->storage)) {
$this->storage = $this->createStorage();
$storage = $this->createStorage(); //FIXME: start using exceptions
if (is_null($storage)) {
return null;
}
$this->storage = $storage;
}
$this->storageId = $this->storage->getId();
if (strlen($this->storageId) > 64) {

View File

@@ -95,6 +95,9 @@ class Local extends \OC\Files\Storage\Common{
// sets the modification time of the file to the given value.
// If mtime is nil the current time is set.
// note that the access time of the file always changes to the current time.
if($this->file_exists($path) and !$this->isUpdatable($path)) {
return false;
}
if(!is_null($mtime)) {
$result=touch( $this->datadir.$path, $mtime );
}else{

View File

@@ -50,7 +50,7 @@ class MappedLocal extends \OC\Files\Storage\Common{
continue;
}
$logicalFilePath = $this->mapper->physicalToLogic($physicalPath.DIRECTORY_SEPARATOR.$file);
$logicalFilePath = $this->mapper->physicalToLogic($physicalPath.'/'.$file);
$file= $this->mapper->stripRootFolder($logicalFilePath, $logicalPath);
$file = $this->stripLeading($file);
@@ -130,7 +130,7 @@ class MappedLocal extends \OC\Files\Storage\Common{
public function file_get_contents($path) {
return file_get_contents($this->buildPath($path));
}
public function file_put_contents($path, $data) {//trigger_error("$path = ".var_export($path, 1));
public function file_put_contents($path, $data) {
return file_put_contents($this->buildPath($path), $data);
}
public function unlink($path) {
@@ -280,7 +280,7 @@ class MappedLocal extends \OC\Files\Storage\Common{
foreach (scandir($physicalDir) as $item) {
if ($item == '.' || $item == '..')
continue;
$physicalItem = $this->mapper->physicalToLogic($physicalDir.DIRECTORY_SEPARATOR.$item);
$physicalItem = $this->mapper->physicalToLogic($physicalDir.'/'.$item);
$item = substr($physicalItem, strlen($physicalDir)+1);
if(strstr(strtolower($item), strtolower($query)) !== false) {
@@ -331,6 +331,9 @@ class MappedLocal extends \OC\Files\Storage\Common{
if(strpos($path, '/') === 0) {
$path = substr($path, 1);
}
if(strpos($path, '\\') === 0) {
$path = substr($path, 1);
}
if ($path === false) {
return '';
}

View File

@@ -267,7 +267,7 @@ class View {
$path = $this->getRelativePath($absolutePath);
$exists = $this->file_exists($path);
$run = true;
if ($this->fakeRoot == Filesystem::getRoot()) {
if ($this->fakeRoot == Filesystem::getRoot() && ! Cache\Scanner::isIgnoredFile($path) ) {
if (!$exists) {
\OC_Hook::emit(
Filesystem::CLASSNAME,
@@ -295,7 +295,7 @@ class View {
list ($count, $result) = \OC_Helper::streamCopy($data, $target);
fclose($target);
fclose($data);
if ($this->fakeRoot == Filesystem::getRoot()) {
if ($this->fakeRoot == Filesystem::getRoot() && ! Cache\Scanner::isIgnoredFile($path) ) {
if (!$exists) {
\OC_Hook::emit(
Filesystem::CLASSNAME,
@@ -627,7 +627,7 @@ class View {
private function runHooks($hooks, $path, $post = false) {
$prefix = ($post) ? 'post_' : '';
$run = true;
if (Filesystem::$loaded and $this->fakeRoot == Filesystem::getRoot()) {
if (Filesystem::$loaded and $this->fakeRoot == Filesystem::getRoot() && ! Cache\Scanner::isIgnoredFile($path) ) {
foreach ($hooks as $hook) {
if ($hook != 'read') {
\OC_Hook::emit(

View File

@@ -135,7 +135,7 @@ class OC_Installer{
// check if the app is compatible with this version of ownCloud
$version=OC_Util::getVersion();
if(!isset($info['require']) or ($version[0]>$info['require'])) {
if(!isset($info['require']) or !OC_App::isAppVersionCompatible($version, $info['require'])) {
OC_Log::write('core',
'App can\'t be installed because it is not compatible with this version of ownCloud',
OC_Log::ERROR);

View File

@@ -36,7 +36,7 @@
"Offending command was: \"%s\", name: %s, password: %s" => "Fehlerhafter Befehl war: \"%s\", Name: %s, Passwort: %s",
"MS SQL username and/or password not valid: %s" => "MS SQL Benutzername und/oder Password ungültig: %s",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Dein Web-Server ist noch nicht für Datei-Synchronisation bereit, weil die WebDAV-Schnittstelle vermutlich defekt ist.",
"Please double check the <a href='%s'>installation guides</a>." => "Bitte prüfe die <a href='%s'>Instalationsanleitungen</a>.",
"Please double check the <a href='%s'>installation guides</a>." => "Bitte prüfe die <a href='%s'>Installationsanleitungen</a>.",
"seconds ago" => "Gerade eben",
"1 minute ago" => "Vor einer Minute",
"%d minutes ago" => "Vor %d Minuten",

View File

@@ -36,7 +36,7 @@
"Offending command was: \"%s\", name: %s, password: %s" => "Fehlerhafter Befehl war: \"%s\", Name: %s, Passwort: %s",
"MS SQL username and/or password not valid: %s" => "MS SQL Benutzername und/oder Passwort ungültig: %s",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Ihr Web-Server ist noch nicht für Datei-Synchronisation bereit, weil die WebDAV-Schnittstelle vermutlich defekt ist.",
"Please double check the <a href='%s'>installation guides</a>." => "Bitte prüfen Sie die <a href='%s'>Instalationsanleitungen</a>.",
"Please double check the <a href='%s'>installation guides</a>." => "Bitte prüfen Sie die <a href='%s'>Installationsanleitungen</a>.",
"seconds ago" => "Gerade eben",
"1 minute ago" => "Vor einer Minute",
"%d minutes ago" => "Vor %d Minuten",

View File

@@ -70,6 +70,10 @@ class OC_Setup {
$password = htmlspecialchars_decode($options['adminpass']);
$datadir = htmlspecialchars_decode($options['directory']);
if (OC_Util::runningOnWindows()) {
$datadir = rtrim(realpath($datadir), '\\');
}
//use sqlite3 when available, otherise sqlite2 will be used.
if($dbtype=='sqlite' and class_exists('SQLite3')) {
$dbtype='sqlite3';
@@ -329,7 +333,7 @@ class OC_Setup {
//add prefix to the postgresql user name to prevent collisions
$dbusername='oc_'.$username;
//create a new password so we don't need to store the admin config in the config file
$dbpassword=md5(time());
$dbpassword=md5(OC_Util::generate_random_bytes(30));
self::pg_createDBUser($dbusername, $dbpassword, $connection);

View File

@@ -37,6 +37,7 @@ class OC_TemplateLayout extends OC_Template {
} else {
parent::__construct('core', 'layout.base');
}
$versionParameter = '?v=' . md5(implode(OC_Util::getVersion()));
// Add the js files
$jsfiles = self::findJavascriptFiles(OC_Util::$scripts);
$this->assign('jsfiles', array(), false);
@@ -44,20 +45,20 @@ class OC_TemplateLayout extends OC_Template {
$this->append( 'jsfiles', OC_Helper::linkToRoute('js_config'));
}
if (!empty(OC_Util::$core_scripts)) {
$this->append( 'jsfiles', OC_Helper::linkToRemoteBase('core.js', false));
$this->append( 'jsfiles', OC_Helper::linkToRemoteBase('core.js', false) . $versionParameter);
}
foreach($jsfiles as $info) {
$root = $info[0];
$web = $info[1];
$file = $info[2];
$this->append( 'jsfiles', $web.'/'.$file);
$this->append( 'jsfiles', $web.'/'.$file . $versionParameter);
}
// Add the css files
$cssfiles = self::findStylesheetFiles(OC_Util::$styles);
$this->assign('cssfiles', array());
if (!empty(OC_Util::$core_styles)) {
$this->append( 'cssfiles', OC_Helper::linkToRemoteBase('core.css', false));
$this->append( 'cssfiles', OC_Helper::linkToRemoteBase('core.css', false) . $versionParameter);
}
foreach($cssfiles as $info) {
$root = $info[0];
@@ -77,10 +78,10 @@ class OC_TemplateLayout extends OC_Template {
$app = $paths[0];
unset($paths[0]);
$path = implode('/', $paths);
$this->append( 'cssfiles', OC_Helper::linkTo($app, $path));
$this->append( 'cssfiles', OC_Helper::linkTo($app, $path) . $versionParameter);
}
else {
$this->append( 'cssfiles', $web.'/'.$file);
$this->append( 'cssfiles', $web.'/'.$file . $versionParameter);
}
}
}

View File

@@ -75,7 +75,7 @@ class OC_Util {
public static function getVersion() {
// hint: We only can count up. Reset minor/patchlevel when
// updating major/minor version number.
return array(5, 00, 00);
return array(5, 00, 6);
}
/**
@@ -83,7 +83,7 @@ class OC_Util {
* @return string
*/
public static function getVersionString() {
return '5.0';
return '5.0.5';
}
/**
@@ -278,7 +278,10 @@ class OC_Util {
'hint'=>'Please ask your server administrator to install the module.');
$web_server_restart= false;
}
if(ini_get('safe_mode')) {
if (((strtolower(@ini_get('safe_mode')) == 'on')
|| (strtolower(@ini_get('safe_mode')) == 'yes')
|| (strtolower(@ini_get('safe_mode')) == 'true')
|| (ini_get("safe_mode") == 1 ))) {
$errors[]=array('error'=>'PHP Safe Mode is enabled. ownCloud requires that it is disabled to work properly.',
'hint'=>'PHP Safe Mode is a deprecated and mostly useless setting that should be disabled. Please ask your server administrator to disable it in php.ini or in your webserver config.');
$web_server_restart= false;
@@ -630,16 +633,26 @@ class OC_Util {
* Check if the ownCloud server can connect to the internet
*/
public static function isinternetconnectionworking() {
$proxy = OC_Config::getValue('proxy', '');
if($proxy <> '') {
list($proxy_host, $proxy_port) = explode(':',$proxy);
$connected = @fsockopen($proxy_host, $proxy_port, $errno, $errstr, 5);
if ($connected) {
fclose($connected);
return true;
}
\OC_Log::write('core', 'Couldn\'t connect to proxy server', \OC_log::WARN);
return false;
}
// try to connect to owncloud.org to see if http connections to the internet are possible.
$connected = @fsockopen("www.owncloud.org", 80);
$connected = @fsockopen("www.owncloud.org", 80, $errno, $errstr, 10);
if ($connected) {
fclose($connected);
return true;
}else{
// second try in case one server is down
$connected = @fsockopen("apps.owncloud.com", 80);
$connected = @fsockopen("apps.owncloud.com", 80, $errno, $errstr, 10);
if ($connected) {
fclose($connected);
return true;

View File

@@ -44,7 +44,7 @@ if (OC_User::isAdminUser(OC_User::getUser())) {
foreach ($batch as $user) {
$users[] = array(
'name' => $user,
'displayname' => OC_User::determineDisplayName($user),
'displayname' => OC_User::getDisplayName($user),
'groups' => join(', ', OC_Group::getUserGroups($user)),
'quota' => OC_Preferences::getValue($user, 'files', 'quota', 'default'));
}

View File

@@ -75,7 +75,13 @@ OC.Settings.Apps = OC.Settings.Apps || {
element.data('active',true);
element.val(t('settings','Disable'));
}
},'json');
},'json')
.fail(function() {
OC.dialogs.alert('Error while enabling app','Error');
element.data('active',false);
OC.Settings.Apps.removeNavigation(appid);
element.val(t('settings','Enable'));
});
$('#leftcontent li[data-id="'+appid+'"]').addClass('active');
}
},
@@ -136,7 +142,9 @@ OC.Settings.Apps = OC.Settings.Apps || {
li.attr('data-id', entry.id);
var img= $('<img class="icon"/>').attr({ src: entry.icon});
var a=$('<a></a>').attr('href', entry.href);
a.text(entry.name);
var filename=$('<span></span>')
filename.text(entry.name);
a.prepend(filename);
a.prepend(img);
li.append(a);
container.append(li);

View File

@@ -4,8 +4,21 @@
* See the COPYING-README file.
*/
function setQuota (uid, quota, ready) {
$.post(
OC.filePath('settings', 'ajax', 'setquota.php'),
{username: uid, quota: quota},
function (result) {
if (ready) {
ready(result.data.quota);
}
}
);
}
var UserList = {
useUndo: true,
availableGroups: [],
/**
* @brief Initiate user deletion process in UI
@@ -71,15 +84,14 @@ var UserList = {
tr.attr('data-uid', username);
tr.attr('data-displayName', displayname);
tr.find('td.name').text(username);
tr.find('td.displayName').text(username);
tr.find('td.displayName').text(displayname);
var groupsSelect = $('<select multiple="multiple" class="groupsselect" data-placehoder="Groups" title="' + t('settings', 'Groups') + '"></select>').attr('data-username', username).attr('data-user-groups', groups);
tr.find('td.groups').empty();
if (tr.find('td.subadmins').length > 0) {
var subadminSelect = $('<select multiple="multiple" class="subadminsselect" data-placehoder="subadmins" title="' + t('settings', 'Group Admin') + '">').attr('data-username', username).attr('data-user-groups', groups).attr('data-subadmin', subadmin);
tr.find('td.subadmins').empty();
}
var allGroups = String($('#content table').attr('data-groups')).split(', ');
$.each(allGroups, function (i, group) {
$.each(this.availableGroups, function (i, group) {
groupsSelect.append($('<option value="' + escapeHTML(group) + '">' + escapeHTML(group) + '</option>'));
if (typeof subadminSelect !== 'undefined' && group != 'admin') {
subadminSelect.append($('<option value="' + escapeHTML(group) + '">' + escapeHTML(group) + '</option>'));
@@ -114,30 +126,78 @@ var UserList = {
quotaSelect.append('<option value="' + escapeHTML(quota) + '" selected="selected">' + escapeHTML(quota) + '</option>');
}
}
var added = false;
$(tr).appendTo('tbody');
if (sort) {
displayname = displayname.toLowerCase();
$('tbody tr').each(function () {
if (displayname < $(this).attr('data-uid').toLowerCase()) {
$(tr).insertBefore($(this));
added = true;
return false;
}
});
UserList.doSort();
}
if (!added) {
$(tr).appendTo('tbody');
}
return tr;
},
update: function () {
if (typeof UserList.offset === 'undefined') {
UserList.offset = $('tbody tr').length;
quotaSelect.singleSelect();
quotaSelect.on('change', function () {
var uid = $(this).parent().parent().attr('data-uid');
var quota = $(this).val();
setQuota(uid, quota);
});
},
// From http://my.opera.com/GreyWyvern/blog/show.dml/1671288
alphanum: function(a, b) {
function chunkify(t) {
var tz = [], x = 0, y = -1, n = 0, i, j;
while (i = (j = t.charAt(x++)).charCodeAt(0)) {
var m = (i == 46 || (i >=48 && i <= 57));
if (m !== n) {
tz[++y] = "";
n = m;
}
tz[y] += j;
}
return tz;
}
var aa = chunkify(a.toLowerCase());
var bb = chunkify(b.toLowerCase());
for (x = 0; aa[x] && bb[x]; x++) {
if (aa[x] !== bb[x]) {
var c = Number(aa[x]), d = Number(bb[x]);
if (c == aa[x] && d == bb[x]) {
return c - d;
} else return (aa[x] > bb[x]) ? 1 : -1;
}
}
return aa.length - bb.length;
},
doSort: function() {
var self = this;
var rows = $('tbody tr').get();
rows.sort(function(a, b) {
return UserList.alphanum($(a).find('td.name').text(), $(b).find('td.name').text());
});
var items = [];
$.each(rows, function(index, row) {
items.push(row);
if(items.length === 100) {
$('tbody').append(items);
items = [];
}
});
if(items.length > 0) {
$('tbody').append(items);
}
},
update: function () {
if (UserList.updating) {
return;
}
UserList.updating = true;
$.get(OC.Router.generate('settings_ajax_userlist', { offset: UserList.offset }), function (result) {
if (result.status === 'success') {
$.each(result.data, function (index, user) {
if($('tr[data-uid="' + user.name + '"]').length > 0) {
return true;
}
var tr = UserList.add(user.name, user.displayname, user.groups, user.subadmin, user.quota, false);
UserList.offset++;
if (index == 9) {
@@ -147,7 +207,11 @@ var UserList = {
});
}
});
if (result.data.length > 0) {
UserList.doSort();
}
}
UserList.updating = false;
});
},
@@ -172,7 +236,14 @@ var UserList = {
username: user,
group: group
},
function () {
function (response) {
if(response.status === 'success' && response.data.action === 'add') {
if(UserList.availableGroups.indexOf(response.data.gropname) === -1) {
UserList.availableGroups.push(response.data.gropname);
}
} else {
OC.Notification.show(response.data.message);
}
}
);
};
@@ -242,24 +313,15 @@ var UserList = {
$(document).ready(function () {
UserList.doSort();
UserList.availableGroups = $('#content table').attr('data-groups').split(', ');
UserList.offset = $('tbody tr').length;
$('tbody tr:last').bind('inview', function (event, isInView, visiblePartX, visiblePartY) {
OC.Router.registerLoadedCallback(function () {
UserList.update();
});
});
function setQuota (uid, quota, ready) {
$.post(
OC.filePath('settings', 'ajax', 'setquota.php'),
{username: uid, quota: quota},
function (result) {
if (ready) {
ready(result.data.quota);
}
}
);
}
$('select[multiple]').each(function (index, element) {
UserList.applyMultiplySelect($(element));
});
@@ -373,7 +435,11 @@ $(document).ready(function () {
OC.dialogs.alert(result.data.message,
t('settings', 'Error creating user'));
} else {
UserList.add(username, username, result.data.groups, null, 'default', true);
var addedGroups = result.data.groups.split(', ');
UserList.availableGroups = $.unique($.merge(UserList.availableGroups, addedGroups));
if($('tr[data-uid="' + username + '"]').length === 0) {
UserList.add(username, username, result.data.groups, null, 'default', true);
}
}
}
);

View File

@@ -14,15 +14,15 @@
"Admins can't remove themself from the admin group" => "Administratoren können sich nicht selbst aus der Admin-Gruppe löschen.",
"Unable to add user to group %s" => "Der Benutzer konnte nicht zur Gruppe %s hinzugefügt werden",
"Unable to remove user from group %s" => "Der Benutzer konnte nicht aus der Gruppe %s entfernt werden",
"Couldn't update app." => "Die App konnte nicht geupdated werden.",
"Update to {appversion}" => "Update zu {appversion}",
"Couldn't update app." => "Die App konnte nicht aktualisiert werden.",
"Update to {appversion}" => "Aktualisierung zu {appversion}",
"Disable" => "Deaktivieren",
"Enable" => "Aktivieren",
"Please wait...." => "Bitte warten...",
"Updating...." => "Update...",
"Updating...." => "Aktualisieren...",
"Error while updating app" => "Fehler beim Aktualisieren der App",
"Error" => "Fehler",
"Updated" => "Geupdated",
"Updated" => "Aktualisiert",
"Saving..." => "Speichern...",
"deleted" => "gelöscht",
"undo" => "rückgängig machen",
@@ -32,14 +32,14 @@
"Delete" => "Löschen",
"add group" => "Gruppe hinzufügen",
"A valid username must be provided" => "Es muss ein gültiger Benutzername angegeben werden",
"Error creating user" => "Beim anlegen des Benutzers ist ein Fehler aufgetreten",
"Error creating user" => "Beim Anlegen des Benutzers ist ein Fehler aufgetreten",
"A valid password must be provided" => "Es muss ein gültiges Passwort angegeben werden",
"__language_name__" => "Deutsch (Persönlich)",
"Security Warning" => "Sicherheitswarnung",
"Your data directory and your files are probably accessible from the internet. The .htaccess file that ownCloud provides is not working. We strongly suggest that you configure your webserver in a way that the data directory is no longer accessible or you move the data directory outside the webserver document root." => "Dein Datenverzeichnis und Deine Datein sind vielleicht vom Internet aus erreichbar. Die .htaccess Datei, die ownCloud verwendet, arbeitet nicht richtig. Wir schlagen Dir dringend vor, dass Du Deinen Webserver so konfigurierst, dass das Datenverzeichnis nicht länger erreichbar ist oder, dass Du Dein Datenverzeichnis aus dem Dokumenten-root des Webservers bewegst.",
"Setup Warning" => "Einrichtungswarnung",
"Your web server is not yet properly setup to allow files synchronization because the WebDAV interface seems to be broken." => "Dein Web-Server ist noch nicht für Datei-Synchronisation bereit, weil die WebDAV-Schnittstelle vermutlich defekt ist.",
"Please double check the <a href='%s'>installation guides</a>." => "Bitte prüfen Sie die <a href='%s'>Instalationsanleitungen</a>.",
"Please double check the <a href='%s'>installation guides</a>." => "Bitte prüfe die <a href='%s'>Instalationsanleitungen</a>.",
"Module 'fileinfo' missing" => "Modul 'fileinfo' fehlt ",
"The PHP module 'fileinfo' is missing. We strongly recommend to enable this module to get best results with mime-type detection." => "Das PHP-Modul 'fileinfo' fehlt. Wir empfehlen dieses Modul zu aktivieren um die besten Resultate bei der Erkennung der Dateitypen zu erreichen.",
"Locale not working" => "Ländereinstellung funktioniert nicht",
@@ -49,20 +49,20 @@
"Cron" => "Cron",
"Execute one task with each page loaded" => "Führe eine Aufgabe mit jeder geladenen Seite aus",
"cron.php is registered at a webcron service. Call the cron.php page in the owncloud root once a minute over http." => "cron.php ist an einem Webcron-Service registriert. Die cron.php Seite wird einmal pro Minute über http abgerufen.",
"Use systems cron service. Call the cron.php file in the owncloud folder via a system cronjob once a minute." => "Nutze den Cron Systemdienst. Rufe die Datei cron.php im owncloud Ordner einmal pro Minute über einen Cronjob auf.",
"Use systems cron service. Call the cron.php file in the owncloud folder via a system cronjob once a minute." => "Verwende den Cron Systemdienst. Rufe die Datei cron.php im owncloud Ordner einmal pro Minute über einen Cronjob auf.",
"Sharing" => "Teilen",
"Enable Share API" => "Aktiviere Sharing-API",
"Allow apps to use the Share API" => "Erlaube Apps die Nutzung der Share-API",
"Allow links" => "Erlaube Links",
"Allow users to share items to the public with links" => "Erlaube Benutzern Inhalte über öffentliche Links zu teilen",
"Allow resharing" => "Erlaube erneutes teilen",
"Allow users to share items shared with them again" => "Erlaube Benutzern mit ihnen geteilte Inhalte erneut zu teilen",
"Allow users to share with anyone" => "Erlaube Benutzern mit jedem zu teilen",
"Allow users to only share with users in their groups" => "Erlaube Benutzern nur mit Benutzern ihrer Gruppe zu teilen",
"Allow users to share items to the public with links" => "Erlaube Benutzern, Inhalte über öffentliche Links zu teilen",
"Allow resharing" => "Erlaube erneutes Teilen",
"Allow users to share items shared with them again" => "Erlaube Benutzern, mit ihnen geteilte Inhalte erneut zu teilen",
"Allow users to share with anyone" => "Erlaube Benutzern, mit jedem zu teilen",
"Allow users to only share with users in their groups" => "Erlaube Benutzern, nur mit Benutzern ihrer Gruppe zu teilen",
"Security" => "Sicherheit",
"Enforce HTTPS" => "Erzwinge HTTPS",
"Enforces the clients to connect to ownCloud via an encrypted connection." => "Erzwingt die Verwendung einer verschlüsselten Verbindung",
"Please connect to this ownCloud instance via HTTPS to enable or disable the SSL enforcement." => "Bitte verbinden Sie sich über eine HTTPS Verbindung mit diesem ownCloud Server um diese Einstellung zu ändern",
"Please connect to this ownCloud instance via HTTPS to enable or disable the SSL enforcement." => "Bitte verbinde Dich über eine HTTPS Verbindung mit diesem ownCloud Server um diese Einstellung zu ändern",
"Log" => "Log",
"Log level" => "Loglevel",
"More" => "Mehr",
@@ -91,7 +91,7 @@
"Change password" => "Passwort ändern",
"Display Name" => "Anzeigename",
"Your display name was changed" => "Dein Anzeigename wurde geändert",
"Unable to change your display name" => "Das Ändern deines Anzeigenamens ist nicht möglich",
"Unable to change your display name" => "Das Ändern Deines Anzeigenamens ist nicht möglich",
"Change display name" => "Anzeigenamen ändern",
"Email" => "E-Mail",
"Your email address" => "Deine E-Mail-Adresse",

View File

@@ -14,13 +14,13 @@
"Admins can't remove themself from the admin group" => "Administratoren können sich nicht selbst aus der admin-Gruppe löschen",
"Unable to add user to group %s" => "Der Benutzer konnte nicht zur Gruppe %s hinzugefügt werden",
"Unable to remove user from group %s" => "Der Benutzer konnte nicht aus der Gruppe %s entfernt werden",
"Couldn't update app." => "Die App konnte nicht geupdated werden.",
"Update to {appversion}" => "Update zu {appversion}",
"Couldn't update app." => "Die App konnte nicht aktualisiert werden.",
"Update to {appversion}" => "Aktualisierung zu {appversion}",
"Disable" => "Deaktivieren",
"Enable" => "Aktivieren",
"Please wait...." => "Bitte warten....",
"Updating...." => "Update...",
"Error while updating app" => "Es ist ein Fehler während des Updates aufgetreten",
"Updating...." => "Aktualisieren...",
"Error while updating app" => "Fehler beim Aktualisieren der App",
"Error" => "Fehler",
"Updated" => "Aktualisiert",
"Saving..." => "Speichern...",
@@ -32,7 +32,7 @@
"Delete" => "Löschen",
"add group" => "Gruppe hinzufügen",
"A valid username must be provided" => "Es muss ein gültiger Benutzername angegeben werden",
"Error creating user" => "Beim Erstellen des Benutzers ist ein Fehler aufgetreten",
"Error creating user" => "Beim Anlegen des Benutzers ist ein Fehler aufgetreten",
"A valid password must be provided" => "Es muss ein gültiges Passwort angegeben werden",
"__language_name__" => "Deutsch (Förmlich: Sie)",
"Security Warning" => "Sicherheitshinweis",
@@ -49,16 +49,16 @@
"Cron" => "Cron",
"Execute one task with each page loaded" => "Führe eine Aufgabe bei jedem Laden der Seite aus",
"cron.php is registered at a webcron service. Call the cron.php page in the owncloud root once a minute over http." => "cron.php ist bei einem Webcron-Service registriert. Die cron.php Seite im ownCloud Wurzelverzeichniss wird einmal pro Minute über http abgerufen.",
"Use systems cron service. Call the cron.php file in the owncloud folder via a system cronjob once a minute." => "Nutzen Sie den Cron Systemdienst. Rufen Sie die Datei cron.php im ownCloud Ordner einmal pro Minute über einen Cronjob auf.",
"Use systems cron service. Call the cron.php file in the owncloud folder via a system cronjob once a minute." => "Verwenden Sie den Cron Systemdienst. Rufen Sie die Datei cron.php im ownCloud Ordner einmal pro Minute über einen Cronjob auf.",
"Sharing" => "Teilen",
"Enable Share API" => "Share-API aktivieren",
"Allow apps to use the Share API" => "Erlaube es Anwendungen, die Share-API zu benutzen",
"Allow links" => "Links erlauben",
"Allow users to share items to the public with links" => "Erlaube es Benutzern, Items per öffentlichem Link zu teilen",
"Allow users to share items to the public with links" => "Erlaube es Benutzern, Inhalte per öffentlichem Link zu teilen",
"Allow resharing" => "Erlaube weiterverteilen",
"Allow users to share items shared with them again" => "Erlaubt Nutzern mit ihnen geteilte Inhalte erneut zu teilen",
"Allow users to share with anyone" => "Erlaube Nutzern mit jedem zu teilen",
"Allow users to only share with users in their groups" => "Erlaube Nutzern nur mit Nutzern in ihrer Gruppe zu teilen",
"Allow users to share items shared with them again" => "Erlaubt Benutzern, mit ihnen geteilte Inhalte erneut zu teilen",
"Allow users to share with anyone" => "Erlaube Benutzern, mit jedem zu teilen",
"Allow users to only share with users in their groups" => "Erlaube Benutzern, nur mit Nutzern in ihrer Gruppe zu teilen",
"Security" => "Sicherheit",
"Enforce HTTPS" => "HTTPS erzwingen",
"Enforces the clients to connect to ownCloud via an encrypted connection." => "Zwingt die Clients, sich über eine verschlüsselte Verbindung mit ownCloud zu verbinden.",

View File

@@ -229,7 +229,7 @@ endfor;?>
<fieldset class="personalblock">
<legend><strong><?php p($l->t('Version'));?></strong></legend>
<strong>ownCloud</strong> <?php p(OC_Util::getVersionString()); ?> <?php p(OC_Util::getEditionString()); ?>
(<?php p(OC_Updater::ShowUpdatingHint()); ?>)<br/>
(<?php print_unescaped(OC_Updater::ShowUpdatingHint()); ?>)<br/>
<?php print_unescaped($l->t('Developed by the <a href="http://ownCloud.org/contact" target="_blank">ownCloud community</a>, the <a href="https://github.com/owncloud" target="_blank">source code</a> is licensed under the <a href="http://www.gnu.org/licenses/agpl-3.0.html" target="_blank"><abbr title="Affero General Public License">AGPL</abbr></a>.')); ?>
</fieldset>

View File

@@ -55,7 +55,7 @@ $_['subadmingroups'] = array_flip($items);
<?php p($_['default_quota']);?>
</option>
<?php endif;?>
<option value='other'>
<option data-new value='other'>
<?php p($l->t('Other'));?>
...
</option>

View File

@@ -64,6 +64,14 @@ class Test_App extends PHPUnit_Framework_TestCase {
}
public function testIsAppVersionCompatibleShouldWorkForPreAlpha(){
$oc = array(5, 0, 3);
$app = '4.93';
$this->assertTrue(OC_App::isAppVersionCompatible($oc, $app));
}
public function testIsAppVersionCompatibleShouldFailOneVersionNumbers(){
$oc = array(4, 3, 1);
$app = '5';

View File

@@ -8,6 +8,7 @@
require_once 'archive.php';
if (!OC_Util::runningOnWindows()) {
class Test_Archive_TAR extends Test_Archive {
protected function getExisting() {
$dir = OC::$SERVERROOT . '/tests/data';
@@ -18,3 +19,4 @@ class Test_Archive_TAR extends Test_Archive {
return new OC_Archive_TAR(OCP\Files::tmpFile('.tar.gz'));
}
}
}

View File

@@ -8,6 +8,7 @@
require_once 'archive.php';
if (!OC_Util::runningOnWindows()) {
class Test_Archive_ZIP extends Test_Archive {
protected function getExisting() {
$dir = OC::$SERVERROOT . '/tests/data';
@@ -18,3 +19,4 @@ class Test_Archive_ZIP extends Test_Archive {
return new OC_Archive_ZIP(OCP\Files::tmpFile('.zip'));
}
}
}

19
tests/lib/autoloader.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
/**
* Copyright (c) 2013 Thomas Müller <thomas.mueller@tmit.eu>
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
*/
class Test_AutoLoader extends PHPUnit_Framework_TestCase {
public function testLeadingSlashOnClassName(){
$this->assertTrue(class_exists('\OC\Files\Storage\Local'));
}
public function testNoLeadingSlashOnClassName(){
$this->assertTrue(class_exists('OC\Files\Storage\Local'));
}
}

View File

@@ -54,6 +54,8 @@ class Updater extends \PHPUnit_Framework_TestCase {
Filesystem::clearMounts();
Filesystem::mount($this->storage, array(), '/' . self::$user . '/files');
\OC_Hook::clear('OC_Filesystem');
\OC_Hook::connect('OC_Filesystem', 'post_write', '\OC\Files\Cache\Updater', 'writeHook');
\OC_Hook::connect('OC_Filesystem', 'post_delete', '\OC\Files\Cache\Updater', 'deleteHook');
\OC_Hook::connect('OC_Filesystem', 'post_rename', '\OC\Files\Cache\Updater', 'renameHook');
@@ -137,11 +139,10 @@ class Updater extends \PHPUnit_Framework_TestCase {
$this->assertFalse($this->cache->inCache('foo.txt'));
$this->assertTrue($this->cache->inCache('bar.txt'));
$cachedData = $this->cache->get('bar.txt');
$this->assertNotEquals($fooCachedData['etag'], $cachedData['etag']);
$this->assertEquals($fooCachedData['fileid'], $cachedData['fileid']);
$mtime = $cachedData['mtime'];
$cachedData = $this->cache->get('');
$this->assertEquals(3 * $textSize + $imageSize, $cachedData['size']);
$this->assertNotEquals($rootCachedData['etag'], $cachedData['etag']);
$this->assertEquals($mtime, $cachedData['mtime']);
}
}

View File

@@ -0,0 +1,52 @@
<?php
/**
* ownCloud
*
* @author Thomas Müller
* @copyright 2013 Thomas Müller thomas.mueller@owncloud.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace Test\Files;
class Mapper extends \PHPUnit_Framework_TestCase {
/**
* @var \OC\Files\Mapper
*/
private $mapper = null;
public function setUp() {
$this->mapper = new \OC\Files\Mapper('D:/');
}
public function testSlugifyPath() {
// with extension
$this->assertEquals('D:/text.txt', $this->mapper->slugifyPath('D:/text.txt'));
$this->assertEquals('D:/text-2.txt', $this->mapper->slugifyPath('D:/text.txt', 2));
$this->assertEquals('D:/a/b/text.txt', $this->mapper->slugifyPath('D:/a/b/text.txt'));
// without extension
$this->assertEquals('D:/text', $this->mapper->slugifyPath('D:/text'));
$this->assertEquals('D:/text-2', $this->mapper->slugifyPath('D:/text', 2));
$this->assertEquals('D:/a/b/text', $this->mapper->slugifyPath('D:/a/b/text'));
// with double dot
$this->assertEquals('D:/text-text.txt', $this->mapper->slugifyPath('D:/text.text.txt'));
$this->assertEquals('D:/text-text-2.txt', $this->mapper->slugifyPath('D:/text.text.txt', 2));
$this->assertEquals('D:/a/b/text-text.txt', $this->mapper->slugifyPath('D:/a/b/text.text.txt'));
}
}

View File

@@ -224,8 +224,7 @@ abstract class Storage extends \PHPUnit_Framework_TestCase {
}
public function testSearchInSubFolder() {
$this->instance->mkdir('sub')
;
$this->instance->mkdir('sub');
$textFile = \OC::$SERVERROOT . '/tests/data/lorem.txt';
$this->instance->file_put_contents('/sub/lorem.txt', file_get_contents($textFile, 'r'));
$pngFile = \OC::$SERVERROOT . '/tests/data/logo-wide.png';
@@ -258,4 +257,10 @@ abstract class Storage extends \PHPUnit_Framework_TestCase {
$content = stream_get_contents($fh);
$this->assertEquals(file_get_contents($textFile), $content);
}
public function testTouchCreateFile(){
$this->assertFalse($this->instance->file_exists('foo'));
$this->instance->touch('foo');
$this->assertTrue($this->instance->file_exists('foo'));
}
}