mirror of
https://github.com/chylex/Nextcloud-Desktop.git
synced 2026-04-04 12:11:33 +02:00
Compare commits
63 Commits
v2.6.1-rc1
...
2.6.2-buil
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de8a7aa680 | ||
|
|
03b11693a3 | ||
|
|
23f2d79f70 | ||
|
|
f6db365391 | ||
|
|
95f74ceb1f | ||
|
|
91be4961d7 | ||
|
|
b3eb16bfd3 | ||
|
|
52d91ce198 | ||
|
|
c49efcc137 | ||
|
|
c14556153f | ||
|
|
5e1a2a423f | ||
|
|
3ac1ba079a | ||
|
|
b7a9cd1d45 | ||
|
|
c7b0ce036d | ||
|
|
f5afa07b0a | ||
|
|
1b550b976f | ||
|
|
68f0b9e0aa | ||
|
|
8945ef2652 | ||
|
|
0cc74d21a2 | ||
|
|
f4c79c8f68 | ||
|
|
b6ef8edb12 | ||
|
|
06ffd3e841 | ||
|
|
a3596b80e9 | ||
|
|
8ac1d92161 | ||
|
|
d55f1d5c06 | ||
|
|
854c637c73 | ||
|
|
92ad0c4a43 | ||
|
|
fb8facb787 | ||
|
|
30832cc427 | ||
|
|
ab7f29c0b2 | ||
|
|
6500442217 | ||
|
|
0e6a9fd0c1 | ||
|
|
ed7c489722 | ||
|
|
d4b9b5129a | ||
|
|
4a79e24db2 | ||
|
|
215d185fbe | ||
|
|
6f273bf7dd | ||
|
|
f2bc25c9ca | ||
|
|
ca6de6128f | ||
|
|
a1e5e6ca40 | ||
|
|
cf8bb1c5bc | ||
|
|
ebe1cef357 | ||
|
|
922d14f016 | ||
|
|
7a0c6a2f8f | ||
|
|
f35a2c0b2c | ||
|
|
c6b22089e3 | ||
|
|
cf0082f92f | ||
|
|
f4e129d4e2 | ||
|
|
ec6eaf2121 | ||
|
|
1dc1f91620 | ||
|
|
5adbc01ef1 | ||
|
|
c4a04bfd05 | ||
|
|
03711429f4 | ||
|
|
e3cb040c3c | ||
|
|
83a21179fa | ||
|
|
829da85aa5 | ||
|
|
3b1ac89312 | ||
|
|
57df29e7c9 | ||
|
|
d774067004 | ||
|
|
728154386c | ||
|
|
bc31182c63 | ||
|
|
a6bb84080a | ||
|
|
576ba7c011 |
31
.drone.yml
31
.drone.yml
@@ -237,13 +237,17 @@ name: qt-5.12
|
||||
|
||||
steps:
|
||||
- name: build and test
|
||||
image: nextcloudci/client-5.12:client-5.12-2
|
||||
image: nextcloudci/client-5.12:client-5.12-5
|
||||
commands:
|
||||
# Install QtKeyChain
|
||||
- /bin/bash -c "
|
||||
export CC=gcc-7 &&
|
||||
export CXX=g++-7 &&
|
||||
source /opt/qt512/bin/qt512-env.sh &&
|
||||
export QT_BASE_DIR=/opt/qt5.12.5 &&
|
||||
export QTDIR=\$QT_BASE_DIR &&
|
||||
export PATH=\$QT_BASE_DIR/bin:\$PATH &&
|
||||
export LD_LIBRARY_PATH=\$QT_BASE_DIR/lib/x86_64-linux-gnu:\$QT_BASE_DIR/lib:/usr/local/lib:\$LD_LIBRARY_PATH &&
|
||||
export PKG_CONFIG_PATH=\$QT_BASE_DIR/lib/pkgconfig:\$PKG_CONFIG_PATH &&
|
||||
cd /tmp &&
|
||||
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
||||
cd qtkeychain &&
|
||||
@@ -257,7 +261,11 @@ steps:
|
||||
- /bin/bash -c "
|
||||
export CC=gcc-7 &&
|
||||
export CXX=g++-7 &&
|
||||
source /opt/qt512/bin/qt512-env.sh &&
|
||||
export QT_BASE_DIR=/opt/qt5.12.5 &&
|
||||
export QTDIR=\$QT_BASE_DIR &&
|
||||
export PATH=\$QT_BASE_DIR/bin:\$PATH &&
|
||||
export LD_LIBRARY_PATH=\$QT_BASE_DIR/lib/x86_64-linux-gnu:\$QT_BASE_DIR/lib:/usr/local/lib:\$LD_LIBRARY_PATH &&
|
||||
export PKG_CONFIG_PATH=\$QT_BASE_DIR/lib/pkgconfig:\$PKG_CONFIG_PATH &&
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -D NO_SHIBBOLETH=1 -DCMAKE_BUILD_TYPE=Debug -DUNIT_TESTING=1 ../ &&
|
||||
@@ -278,13 +286,17 @@ name: qt-5.12-clang
|
||||
|
||||
steps:
|
||||
- name: build and test
|
||||
image: nextcloudci/client-5.12:client-5.12-2
|
||||
image: nextcloudci/client-5.12:client-5.12-5
|
||||
commands:
|
||||
# Install QtKeyChain
|
||||
- /bin/bash -c "
|
||||
export CC=clang-6.0 &&
|
||||
export CXX=clang++-6.0 &&
|
||||
source /opt/qt512/bin/qt512-env.sh &&
|
||||
export QT_BASE_DIR=/opt/qt5.12.5 &&
|
||||
export QTDIR=\$QT_BASE_DIR &&
|
||||
export PATH=\$QT_BASE_DIR/bin:\$PATH &&
|
||||
export LD_LIBRARY_PATH=\$QT_BASE_DIR/lib/x86_64-linux-gnu:\$QT_BASE_DIR/lib:/usr/local/lib:\$LD_LIBRARY_PATH &&
|
||||
export PKG_CONFIG_PATH=\$QT_BASE_DIR/lib/pkgconfig:\$PKG_CONFIG_PATH &&
|
||||
cd /tmp &&
|
||||
git clone https://github.com/frankosterfeld/qtkeychain.git &&
|
||||
cd qtkeychain &&
|
||||
@@ -298,7 +310,11 @@ steps:
|
||||
- /bin/bash -c "
|
||||
export CC=clang-6.0 &&
|
||||
export CXX=clang++-6.0 &&
|
||||
source /opt/qt512/bin/qt512-env.sh &&
|
||||
export QT_BASE_DIR=/opt/qt5.12.5 &&
|
||||
export QTDIR=\$QT_BASE_DIR &&
|
||||
export PATH=\$QT_BASE_DIR/bin:\$PATH &&
|
||||
export LD_LIBRARY_PATH=\$QT_BASE_DIR/lib/x86_64-linux-gnu:\$QT_BASE_DIR/lib:/usr/local/lib:\$LD_LIBRARY_PATH &&
|
||||
export PKG_CONFIG_PATH=\$QT_BASE_DIR/lib/pkgconfig:\$PKG_CONFIG_PATH &&
|
||||
mkdir build &&
|
||||
cd build &&
|
||||
cmake -D NO_SHIBBOLETH=1 -DCMAKE_BUILD_TYPE=Debug -DUNIT_TESTING=1 ../ &&
|
||||
@@ -319,9 +335,10 @@ name: AppImage
|
||||
|
||||
steps:
|
||||
- name: build
|
||||
image: nextcloudci/client-5.12:client-5.12-2
|
||||
image: nextcloudci/client-5.12:client-5.12-5
|
||||
commands:
|
||||
- /bin/bash -c "./admin/linux/build-appimage.sh"
|
||||
- /bin/bash -c "./admin/linux/upload-appimage.sh"
|
||||
trigger:
|
||||
branch:
|
||||
- master
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,6 +1,3 @@
|
||||
[submodule "src/3rdparty/qtmacgoodies"]
|
||||
path = src/3rdparty/qtmacgoodies
|
||||
url = https://github.com/camilasan/qtmacgoodies.git
|
||||
[submodule "binary"]
|
||||
path = binary
|
||||
url = git://github.com/owncloud/owncloud-client-binary.git
|
||||
|
||||
204
.tx/nextcloud.client-desktop/cy_GB_translation
Normal file
204
.tx/nextcloud.client-desktop/cy_GB_translation
Normal file
@@ -0,0 +1,204 @@
|
||||
[Desktop Entry]
|
||||
Categories=Utility;X-SuSE-SyncUtility;
|
||||
Type=Application
|
||||
Exec=@APPLICATION_EXECUTABLE@
|
||||
Name=@APPLICATION_NAME@ desktop sync client
|
||||
Comment=@APPLICATION_NAME@ desktop synchronization client
|
||||
GenericName=Folder Sync
|
||||
Icon=@APPLICATION_ICON_NAME@
|
||||
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
|
||||
X-GNOME-Autostart-Delay=3
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
Icon[cy_GB]=@APPLICATION_ICON_NAME@
|
||||
Name[cy_GB]=@APPLICATION_NAME@ cleient cydweddu bwrdd gwaith
|
||||
Comment[cy_GB]=@APPLICATION_NAME@ cleient cydweddu bwrdd gwaith
|
||||
GenericName[cy_GB]=Cydweddu Ffolder
|
||||
@@ -198,7 +198,7 @@ X-GNOME-Autostart-Delay=3
|
||||
|
||||
|
||||
# Translations
|
||||
Icon[de_DE]=@APPLICATION_ICON_NAME@
|
||||
Name[de_DE]=@APPLICATION_NAME@ Client zur Desktop-Synchronisation
|
||||
Comment[de_DE]=@APPLICATION_NAME@ Client zur Desktop-Synchronisation
|
||||
GenericName[de_DE]=Synchronisationsordner
|
||||
Icon[de]=@APPLICATION_ICON_NAME@
|
||||
Name[de]=@APPLICATION_NAME@ Client zur Desktop-Synchronisation
|
||||
Comment[de]=@APPLICATION_NAME@ Client zur Desktop-Synchronisation
|
||||
GenericName[de]=Synchronisationsordner
|
||||
|
||||
@@ -201,4 +201,4 @@ X-GNOME-Autostart-Delay=3
|
||||
Icon[ro]=@APPLICATION_ICON_NAME@
|
||||
Name[ro]=@APPLICATION_NAME@ client de sincronizare pentru desktop
|
||||
Comment[ro]=@APPLICATION_NAME@ client de sincronizare pentru desktop
|
||||
GenericName[ro]=Sincronizare dosare
|
||||
GenericName[ro]=Sincronizare director
|
||||
|
||||
@@ -201,4 +201,4 @@ X-GNOME-Autostart-Delay=3
|
||||
Icon[sk_SK]=@APPLICATION_ICON_NAME@
|
||||
Name[sk_SK]=@APPLICATION_NAME@ synchronizačný klient pre PC
|
||||
Comment[sk_SK]=@APPLICATION_NAME@ synchronizačný klient pre PC
|
||||
GenericName[sk_SK]=Synchnonizácia priečinkov
|
||||
GenericName[sk_SK]=Synchronizácia priečinkov
|
||||
|
||||
@@ -199,6 +199,6 @@ X-GNOME-Autostart-Delay=3
|
||||
|
||||
# Translations
|
||||
Icon[sl]=@APPLICATION_ICON_NAME@
|
||||
Name[sl]=@APPLICATION_NAME@ odjemalec za usklajevanje
|
||||
Comment[sl]=@APPLICATION_NAME@ odjemalec za usklajevanje
|
||||
Name[sl]=@APPLICATION_NAME@ program za usklajevanje
|
||||
Comment[sl]=@APPLICATION_NAME@ program za usklajevanje
|
||||
GenericName[sl]=Usklajevanje map
|
||||
|
||||
204
.tx/nextcloud.client-desktop/sw_translation
Normal file
204
.tx/nextcloud.client-desktop/sw_translation
Normal file
@@ -0,0 +1,204 @@
|
||||
[Desktop Entry]
|
||||
Categories=Utility;X-SuSE-SyncUtility;
|
||||
Type=Application
|
||||
Exec=@APPLICATION_EXECUTABLE@
|
||||
Name=@APPLICATION_NAME@ desktop sync client
|
||||
Comment=@APPLICATION_NAME@ desktop synchronization client
|
||||
GenericName=Folder Sync
|
||||
Icon=@APPLICATION_ICON_NAME@
|
||||
Keywords=@APPLICATION_NAME@;syncing;file;sharing;
|
||||
X-GNOME-Autostart-Delay=3
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
|
||||
|
||||
# Translations
|
||||
Icon[sw]=@APPLICATION_ICON_NAME@
|
||||
Name[sw]=Teja ya @APPLICATION_NAME@ ya kufanana faili kwa seva na faili ziko hapa
|
||||
Comment[sw]=Teja ya @APPLICATION_NAME@ ya kufanana faili kwa seva na faili ziko hapa
|
||||
GenericName[sw]=Fanana Kabrasha
|
||||
@@ -1,6 +1,6 @@
|
||||
set( MIRALL_VERSION_MAJOR 2 )
|
||||
set( MIRALL_VERSION_MINOR 6 )
|
||||
set( MIRALL_VERSION_PATCH 1 )
|
||||
set( MIRALL_VERSION_PATCH 2 )
|
||||
set( MIRALL_VERSION_YEAR 2019 )
|
||||
set( MIRALL_SOVERSION 0 )
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ RUN apt-get update -q && DEBIAN_FRONTEND=noninteractive apt-get install -q -y --
|
||||
libsqlite3-dev \
|
||||
libssl-dev \
|
||||
libcmocka-dev \
|
||||
libcloudproviders-dev \
|
||||
qt5-default \
|
||||
qttools5-dev-tools \
|
||||
libqt5webkit5-dev \
|
||||
|
||||
@@ -6,7 +6,7 @@ mkdir /app
|
||||
mkdir /build
|
||||
|
||||
#Set Qt-5.12
|
||||
export QT_BASE_DIR=/opt/qt512
|
||||
export QT_BASE_DIR=/opt/qt5.12.5
|
||||
export QTDIR=$QT_BASE_DIR
|
||||
export PATH=$QT_BASE_DIR/bin:$PATH
|
||||
export LD_LIBRARY_PATH=$QT_BASE_DIR/lib/x86_64-linux-gnu:$QT_BASE_DIR/lib:$LD_LIBRARY_PATH
|
||||
@@ -66,7 +66,8 @@ rm -rf ./usr/share/nemo-python/
|
||||
mv ./etc/Nextcloud/sync-exclude.lst ./usr/bin/
|
||||
rm -rf ./etc
|
||||
|
||||
sed -i -e 's|Icon=nextcloud|Icon=Nextcloud|g' usr/share/applications/nextcloud.desktop # Bug in desktop file?
|
||||
DESKTOP_FILE=/app/usr/share/applications/${LINUX_APPLICATION_ID}.desktop
|
||||
sed -i -e 's|Icon=nextcloud|Icon=Nextcloud|g' ${DESKTOP_FILE} # Bug in desktop file?
|
||||
cp ./usr/share/icons/hicolor/512x512/apps/Nextcloud.png . # Workaround for linuxeployqt bug, FIXME
|
||||
|
||||
|
||||
@@ -87,17 +88,12 @@ chmod a+x linuxdeployqt*.AppImage
|
||||
rm ./linuxdeployqt-continuous-x86_64.AppImage
|
||||
unset QTDIR; unset QT_PLUGIN_PATH ; unset LD_LIBRARY_PATH
|
||||
export LD_LIBRARY_PATH=/app/usr/lib/
|
||||
./squashfs-root/AppRun /app/usr/share/applications/nextcloud.desktop -bundle-non-qt-libs
|
||||
./squashfs-root/AppRun ${DESKTOP_FILE} -bundle-non-qt-libs
|
||||
|
||||
# Set origin
|
||||
./squashfs-root/usr/bin/patchelf --set-rpath '$ORIGIN/' /app/usr/lib/libnextcloudsync.so.0
|
||||
|
||||
# Build AppImage
|
||||
./squashfs-root/AppRun /app/usr/share/applications/nextcloud.desktop -appimage
|
||||
./squashfs-root/AppRun ${DESKTOP_FILE} -appimage
|
||||
|
||||
mv Nextcloud*.AppImage Nextcloud-${SUFFIX}-${DRONE_COMMIT}-x86_64.AppImage
|
||||
|
||||
curl --upload-file $(readlink -f ./Nextcloud*.AppImage) https://transfer.sh/Nextcloud-${SUFFIX}-${DRONE_COMMIT}-x86_64.AppImage
|
||||
|
||||
echo
|
||||
echo "Get the AppImage at the link above!"
|
||||
|
||||
@@ -9,6 +9,8 @@ Build-Depends: cmake,
|
||||
extra-cmake-modules (>= 5.16),
|
||||
libkf5kio-dev,
|
||||
libcmocka-dev,
|
||||
libcloudproviders-dev,
|
||||
libdbus-1-dev,
|
||||
libhttp-dav-perl,
|
||||
libinotify-dev [kfreebsd-any],
|
||||
libqt5svg5-dev,
|
||||
|
||||
48
admin/linux/debian/debian.oldstable/changelog
Normal file
48
admin/linux/debian/debian.oldstable/changelog
Normal file
@@ -0,0 +1,48 @@
|
||||
nextcloud-client (2.3.3-1.0~oldstable1) oldstable; urgency=medium
|
||||
|
||||
* Debian build support for the forked client.
|
||||
|
||||
-- István Váradi <ivaradi@varadiistvan.hu> Mon, 6 Nov 2017 20:20:04 +0100
|
||||
|
||||
nextcloud-client (2.3.1-1.0) oldstable; urgency=medium
|
||||
|
||||
* New upstream version
|
||||
|
||||
-- István Váradi <ivaradi@varadiistvan.hu> Thu, 23 Mar 2017 19:07:36 +0100
|
||||
|
||||
nextcloud-client (2.3.0-1.0) oldstable; urgency=medium
|
||||
|
||||
* New upstream version
|
||||
|
||||
-- István Váradi <ivaradi@varadiistvan.hu> Tue, 21 Mar 2017 19:34:13 +0100
|
||||
|
||||
nextcloud-client (2.2.4-1.4) oldstable; urgency=medium
|
||||
|
||||
* The locale-specific icon names are correct too
|
||||
|
||||
-- István Váradi <ivaradi@varadiistvan.hu> Tue, 7 Feb 2017 19:55:40 +0100
|
||||
|
||||
nextcloud-client (2.2.4-1.3) oldstable; urgency=medium
|
||||
|
||||
* Caja syncstate plugin is built.
|
||||
* The syncstate plugin has application-specific name
|
||||
|
||||
-- István Váradi <ivaradi@varadiistvan.hu> Fri, 27 Jan 2017 19:34:18 +0100
|
||||
|
||||
nextcloud-client (2.2.4-1.2) oldstable; urgency=medium
|
||||
|
||||
* Fixed appname in the Nemo syncstate extension.
|
||||
|
||||
-- István Váradi <ivaradi@varadiistvan.hu> Thu, 19 Jan 2017 16:46:50 +0100
|
||||
|
||||
nextcloud-client (2.2.4-1.1) oldstable; urgency=medium
|
||||
|
||||
* Added Nautilus and Nemo syncstate extensions.
|
||||
|
||||
-- István Váradi <ivaradi@varadiistvan.hu> Tue, 17 Jan 2017 19:55:32 +0100
|
||||
|
||||
nextcloud-client (2.2.4-1.0) oldstable; urgency=medium
|
||||
|
||||
* Initial release.
|
||||
|
||||
-- István Váradi <ivaradi@varadiistvan.hu> Wed, 14 Dec 2016 20:07:46 +0100
|
||||
84
admin/linux/debian/debian.oldstable/control
Normal file
84
admin/linux/debian/debian.oldstable/control
Normal file
@@ -0,0 +1,84 @@
|
||||
Source: nextcloud-client
|
||||
Section: contrib/devel
|
||||
Priority: optional
|
||||
Maintainer: István Váradi <ivaradi@varadiistvan.hu>
|
||||
Build-Depends: cmake,
|
||||
debhelper,
|
||||
cdbs,
|
||||
dh-python,
|
||||
extra-cmake-modules (>= 5.16),
|
||||
kdelibs5-dev,
|
||||
kio-dev,
|
||||
libcmocka-dev,
|
||||
libdbus-1-dev,
|
||||
libhttp-dav-perl,
|
||||
libinotify-dev [kfreebsd-any],
|
||||
libqt5webkit5-dev,
|
||||
libqt5svg5-dev,
|
||||
libsqlite3-dev,
|
||||
libssl-dev (>= 1.1.0),
|
||||
zlib1g-dev,
|
||||
optipng,
|
||||
pkg-kde-tools,
|
||||
python-sphinx | python3-sphinx,
|
||||
python3-all,
|
||||
qt5keychain-dev,
|
||||
qtwebengine5-dev,
|
||||
qtdeclarative5-dev,
|
||||
qttools5-dev,
|
||||
qttools5-dev-tools,
|
||||
xvfb
|
||||
Standards-Version: 3.9.8
|
||||
Homepage: https://github.com/nextcloud/client_theming
|
||||
#Vcs-Git: git://anonscm.debian.org/collab-maint/nextcloud-client.git
|
||||
#Vcs-Browser: https://anonscm.debian.org/cgit/collab-maint/nextcloud-client.git
|
||||
|
||||
Package: nextcloud-client
|
||||
Architecture: any
|
||||
Depends: libnextcloudsync0 (=${binary:Version}), ${shlibs:Depends}, ${misc:Depends}, nextcloud-client-l10n
|
||||
Recommends: libgnome-keyring0
|
||||
Description: Nextcloud desktop sync client
|
||||
Use the desktop client to keep your files synchronized
|
||||
between your Nextcloud server and your desktop. Select
|
||||
one or more directories on your local machine and always
|
||||
have access to your latest files wherever you are.
|
||||
|
||||
Package: libnextcloudsync0
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: Nextcloud sync library
|
||||
Used by the Nextcloud desktop client as the synchronization engine.
|
||||
|
||||
Package: libnextcloudsync-dev
|
||||
Architecture: any
|
||||
Section: contrib/libdevel
|
||||
Depends: libnextcloudsync0 (=${binary:Version}), ${misc:Depends}
|
||||
Description: Nextcloud sync library development files
|
||||
The headers and development library for the Nextcloud sync library.
|
||||
|
||||
Package: nextcloud-client-l10n
|
||||
Architecture: all
|
||||
Depends: ${misc:Depends}
|
||||
Description: Nextcloud client internatialization files
|
||||
The translation files.
|
||||
|
||||
Package: nextcloud-client-nautilus
|
||||
Architecture: all
|
||||
Depends: nextcloud-client (>=${binary:Version}), libnextcloudsync0, python-nautilus, nautilus, ${misc:Depends}
|
||||
Description: Nautilus plugin for Nextcloud
|
||||
This package contains a Nautilus plugin to display
|
||||
synchronization status icons for Nextcloud files.
|
||||
|
||||
Package: nextcloud-client-nemo
|
||||
Architecture: all
|
||||
Depends: nextcloud-client (>=${binary:Version}), libnextcloudsync0, python-nemo, nemo, ${misc:Depends}
|
||||
Description: Nemo plugin for Nextcloud
|
||||
This package contains a Nemo plugin to display
|
||||
synchronization status icons for Nextcloud files.
|
||||
|
||||
Package: nextcloud-client-caja
|
||||
Architecture: all
|
||||
Depends: nextcloud-client (>=${binary:Version}), libnextcloudsync0, python-caja, caja, ${misc:Depends}
|
||||
Description: Caja plugin for Nextcloud
|
||||
This package contains a Caja plugin to display
|
||||
synchronization status icons for Nextcloud files.
|
||||
@@ -9,7 +9,10 @@ Build-Depends: cmake,
|
||||
extra-cmake-modules (>= 5.16),
|
||||
kdelibs5-dev,
|
||||
kio-dev,
|
||||
libavcodec58,
|
||||
libcmocka-dev,
|
||||
libcloudproviders-dev,
|
||||
libdbus-1-dev,
|
||||
libhttp-dav-perl,
|
||||
libinotify-dev [kfreebsd-any],
|
||||
libqt5webkit5-dev,
|
||||
|
||||
@@ -10,6 +10,8 @@ Build-Depends: cmake,
|
||||
kdelibs5-dev,
|
||||
libkf5kio-dev,
|
||||
libcmocka-dev,
|
||||
libcloudproviders-dev,
|
||||
libdbus-1-dev,
|
||||
libhttp-dav-perl,
|
||||
libinotify-dev [kfreebsd-any],
|
||||
libqt5svg5-dev,
|
||||
|
||||
@@ -51,7 +51,7 @@ if ! wget http://ppa.launchpad.net/${repo}/ubuntu/pool/main/n/nextcloud-client/n
|
||||
origsourceopt="-sa"
|
||||
fi
|
||||
|
||||
for distribution in xenial bionic disco eoan stable; do
|
||||
for distribution in xenial bionic disco eoan stable oldstable; do
|
||||
rm -rf nextcloud-client_${basever}
|
||||
cp -a ${DRONE_WORKSPACE} nextcloud-client_${basever}
|
||||
|
||||
@@ -98,26 +98,46 @@ if test "${pull_request}" = "master"; then
|
||||
PPA=$PPA_BETA
|
||||
OBS_PROJECT=$OBS_PROJECT_BETA
|
||||
fi
|
||||
OBS_SUBDIR="${OBS_PROJECT}/${OBS_PACKAGE}"
|
||||
|
||||
if test -f ~/.has_ppa_keys; then
|
||||
for changes in nextcloud-client_*~+([a-z])1_source.changes; do
|
||||
dput $PPA $changes > /dev/null
|
||||
case "${changes}" in
|
||||
*oldstable1*)
|
||||
;;
|
||||
*)
|
||||
dput $PPA $changes > /dev/null
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
mkdir osc
|
||||
cd osc
|
||||
osc co ${OBS_PROJECT} ${OBS_PACKAGE}
|
||||
if test "$(ls ${OBS_SUBDIR})"; then
|
||||
osc delete ${OBS_SUBDIR}/*
|
||||
fi
|
||||
cp ../nextcloud-client*.orig.tar.* ${OBS_SUBDIR}/
|
||||
cp ../nextcloud-client_*[0-9.][0-9].dsc ${OBS_SUBDIR}/
|
||||
cp ../nextcloud-client_*[0-9.][0-9].debian.tar* ${OBS_SUBDIR}/
|
||||
cp ../nextcloud-client_*[0-9.][0-9]_source.changes ${OBS_SUBDIR}/
|
||||
osc add ${OBS_SUBDIR}/*
|
||||
for distribution in stable oldstable; do
|
||||
if test "${distribution}" = "oldstable"; then
|
||||
pkgsuffix=".${distribution}"
|
||||
pkgvertag="~${distribution}1"
|
||||
else
|
||||
pkgsuffix=""
|
||||
pkgvertag=""
|
||||
fi
|
||||
|
||||
cd ${OBS_SUBDIR}
|
||||
osc commit -m "Travis update"
|
||||
package="${OBS_PACKAGE}${pkgsuffix}"
|
||||
OBS_SUBDIR="${OBS_PROJECT}/${package}"
|
||||
|
||||
mkdir -p osc
|
||||
pushd osc
|
||||
osc co ${OBS_PROJECT} ${package}
|
||||
if test "$(ls ${OBS_SUBDIR})"; then
|
||||
osc delete ${OBS_SUBDIR}/*
|
||||
fi
|
||||
|
||||
cp ../nextcloud-client*.orig.tar.* ${OBS_SUBDIR}/
|
||||
cp ../nextcloud-client_*[0-9.][0-9]${pkgvertag}.dsc ${OBS_SUBDIR}/
|
||||
cp ../nextcloud-client_*[0-9.][0-9]${pkgvertag}.debian.tar* ${OBS_SUBDIR}/
|
||||
cp ../nextcloud-client_*[0-9.][0-9]${pkgvertag}_source.changes ${OBS_SUBDIR}/
|
||||
osc add ${OBS_SUBDIR}/*
|
||||
|
||||
cd ${OBS_SUBDIR}
|
||||
osc commit -m "Travis update"
|
||||
popd
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
21
admin/linux/upload-appimage.sh
Executable file
21
admin/linux/upload-appimage.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#! /bin/bash
|
||||
|
||||
set -xe
|
||||
|
||||
cd /build
|
||||
|
||||
# Upload AppImage
|
||||
APPIMAGE=$(readlink -f ./Nextcloud*.AppImage)
|
||||
BASENAME=$(basename ${APPIMAGE})
|
||||
|
||||
if curl --max-time 900 --upload-file ${APPIMAGE} https://transfer.sh/${BASENAME}
|
||||
then
|
||||
echo
|
||||
echo "Get the AppImage at the link above!"
|
||||
else
|
||||
echo
|
||||
echo "Upload failed, however this is an optional step."
|
||||
fi
|
||||
|
||||
# Don't let the Drone build fail
|
||||
exit 0
|
||||
@@ -49,7 +49,7 @@ fi
|
||||
if [ ! -z "$identity" ]; then
|
||||
echo "Will try to sign the installer"
|
||||
pushd $install_path
|
||||
productsign --sign "$identity" "$installer_file" "$installer_file.new"
|
||||
productsign --timestamp --sign "$identity" "$installer_file" "$installer_file.new"
|
||||
mv "$installer_file".new "$installer_file"
|
||||
popd
|
||||
else
|
||||
|
||||
2
binary
2
binary
Submodule binary updated: 3425fab2c6...09f12de312
@@ -27,7 +27,7 @@
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>@MIRALL_VERSION_STRING@</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>(C) 2014-2018 @APPLICATION_VENDOR@</string>
|
||||
<string>(C) 2014-2019 @APPLICATION_VENDOR@</string>
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
<true/>
|
||||
<key>SUShowReleaseNotes</key>
|
||||
|
||||
@@ -467,6 +467,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = FinderSyncExt/FinderSyncExt.entitlements;
|
||||
CODE_SIGN_IDENTITY = "-";
|
||||
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
|
||||
@@ -35,11 +35,11 @@ public:
|
||||
|
||||
QString contextMenuTitle() const
|
||||
{
|
||||
return _strings.value("CONTEXT_MENU_TITLE", "ownCloud");
|
||||
return _strings.value("CONTEXT_MENU_TITLE", "Nextcloud");
|
||||
}
|
||||
QString shareActionTitle() const
|
||||
{
|
||||
return _strings.value("SHARE_MENU_TITLE", "Share...");
|
||||
return _strings.value("SHARE_MENU_TITLE", "Share …");
|
||||
}
|
||||
|
||||
QString copyPrivateLinkTitle() const { return _strings["COPY_PRIVATE_LINK_MENU_TITLE"]; }
|
||||
|
||||
2
src/3rdparty/libcrashreporter-qt
vendored
2
src/3rdparty/libcrashreporter-qt
vendored
Submodule src/3rdparty/libcrashreporter-qt updated: 7df66f72aa...a4409c5c1b
1
src/3rdparty/qtmacgoodies
vendored
1
src/3rdparty/qtmacgoodies
vendored
Submodule src/3rdparty/qtmacgoodies deleted from ebc7ec6f68
@@ -29,6 +29,11 @@ if(NOT MSVC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_FORTIFY_SOURCE=2")
|
||||
endif()
|
||||
|
||||
# Calling Qt's qCWarning(category, ...) with no params for "..." is a GNU
|
||||
# extension (C++11 §16.3/4 forbids them). Silence clang's warnings.
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-gnu-zero-variadic-macro-arguments")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-gnu-zero-variadic-macro-arguments")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
|
||||
@@ -288,7 +288,11 @@ void ExcludedFiles::addManualExclude(const QByteArray &expr)
|
||||
|
||||
void ExcludedFiles::addManualExclude(const QByteArray &expr, const QByteArray &basePath)
|
||||
{
|
||||
#if defined(Q_OS_WIN)
|
||||
Q_ASSERT(basePath.size() >= 2 && basePath.at(1) == ':');
|
||||
#else
|
||||
Q_ASSERT(basePath.startsWith('/'));
|
||||
#endif
|
||||
Q_ASSERT(basePath.endsWith('/'));
|
||||
|
||||
auto key = basePath;
|
||||
|
||||
@@ -104,6 +104,7 @@ set(client_SRCS
|
||||
guiutility.cpp
|
||||
elidedlabel.cpp
|
||||
iconjob.cpp
|
||||
remotewipe.cpp
|
||||
creds/credentialsfactory.cpp
|
||||
creds/httpcredentialsgui.cpp
|
||||
creds/oauth.cpp
|
||||
@@ -144,8 +145,6 @@ set(updater_SRCS
|
||||
|
||||
IF( APPLE )
|
||||
list(APPEND client_SRCS cocoainitializer_mac.mm)
|
||||
list(APPEND client_SRCS settingsdialogmac.cpp)
|
||||
list(REMOVE_ITEM client_SRCS settingsdialog.cpp)
|
||||
list(APPEND client_SRCS socketapisocket_mac.mm)
|
||||
list(APPEND client_SRCS systray.mm)
|
||||
|
||||
@@ -175,17 +174,6 @@ set(3rdparty_SRC
|
||||
../3rdparty/kmessagewidget/kmessagewidget.cpp
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
list(APPEND 3rdparty_SRC
|
||||
../3rdparty/qtmacgoodies/src/macpreferenceswindow.mm
|
||||
../3rdparty/qtmacgoodies/src/macstandardicon.mm
|
||||
../3rdparty/qtmacgoodies/src/macwindow.mm
|
||||
)
|
||||
# We want to access Cocoa specific structures in the code above
|
||||
# and need the platform plugin interface for that - which is private.
|
||||
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if(NOT WIN32)
|
||||
list(APPEND 3rdparty_SRC ../3rdparty/qtlockedfile/qtlockedfile_unix.cpp)
|
||||
else()
|
||||
@@ -341,7 +329,6 @@ ENDIF()
|
||||
target_include_directories(${APPLICATION_EXECUTABLE} PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/src/3rdparty/QProgressIndicator
|
||||
${CMAKE_SOURCE_DIR}/src/3rdparty/qtlockedfile
|
||||
${CMAKE_SOURCE_DIR}/src/3rdparty/qtmacgoodies/src
|
||||
${CMAKE_SOURCE_DIR}/src/3rdparty/qtsingleapplication
|
||||
${CMAKE_SOURCE_DIR}/src/3rdparty/kmessagewidget
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
|
||||
@@ -368,6 +368,7 @@ void AccountManager::shutdown()
|
||||
_accounts.clear();
|
||||
foreach (const auto &acc, accountsCopy) {
|
||||
emit accountRemoved(acc.data());
|
||||
emit removeAccountFolders(acc.data());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,6 @@ public:
|
||||
*/
|
||||
void deleteAccount(AccountState *account);
|
||||
|
||||
|
||||
/**
|
||||
* Creates an account and sets up some basic handlers.
|
||||
* Does *not* add the account to the account manager just yet.
|
||||
@@ -104,6 +103,7 @@ public slots:
|
||||
Q_SIGNALS:
|
||||
void accountAdded(AccountState *account);
|
||||
void accountRemoved(AccountState *account);
|
||||
void removeAccountFolders(AccountState *account);
|
||||
|
||||
private:
|
||||
AccountManager() {}
|
||||
|
||||
@@ -57,10 +57,6 @@
|
||||
|
||||
#include "account.h"
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
#include "settingsdialogmac.h"
|
||||
#endif
|
||||
|
||||
namespace OCC {
|
||||
|
||||
Q_LOGGING_CATEGORY(lcAccountSettings, "nextcloud.gui.account.settings", QtInfoMsg)
|
||||
@@ -147,6 +143,8 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
|
||||
createAccountToolbox();
|
||||
connect(AccountManager::instance(), &AccountManager::accountAdded,
|
||||
this, &AccountSettings::slotAccountAdded);
|
||||
connect(this, &AccountSettings::removeAccountFolders,
|
||||
AccountManager::instance(), &AccountManager::removeAccountFolders);
|
||||
connect(ui->_folderList, &QWidget::customContextMenuRequested,
|
||||
this, &AccountSettings::slotCustomContextMenuRequested);
|
||||
connect(ui->_folderList, &QAbstractItemView::clicked,
|
||||
@@ -204,6 +202,8 @@ AccountSettings::AccountSettings(AccountState *accountState, QWidget *parent)
|
||||
} else {
|
||||
ui->encryptionMessage->hide();
|
||||
}
|
||||
|
||||
customizeStyle();
|
||||
}
|
||||
|
||||
|
||||
@@ -278,16 +278,7 @@ void AccountSettings::slotOpenAccountWizard()
|
||||
if (qgetenv("QT_QPA_PLATFORMTHEME") == "appmenu-qt5" || QSystemTrayIcon::isSystemTrayAvailable()) {
|
||||
topLevelWidget()->close();
|
||||
}
|
||||
#ifdef Q_OS_MAC
|
||||
qCDebug(lcAccountSettings) << parent() << topLevelWidget();
|
||||
SettingsDialogMac *sd = qobject_cast<SettingsDialogMac *>(topLevelWidget());
|
||||
|
||||
if (sd) {
|
||||
sd->showActivityPage();
|
||||
} else {
|
||||
qFatal("nope");
|
||||
}
|
||||
#endif
|
||||
OwncloudSetupWizard::runWizard(qApp, SLOT(slotownCloudWizardDone(int)), nullptr);
|
||||
}
|
||||
|
||||
@@ -334,9 +325,9 @@ void AccountSettings::slotEncryptionFlagError(const QByteArray& fileId, int http
|
||||
|
||||
void AccountSettings::slotLockForEncryptionSuccess(const QByteArray& fileId, const QByteArray &token)
|
||||
{
|
||||
accountsState()->account()->e2e()->setTokenForFolder(fileId, token);
|
||||
accountsState()->account()->e2e()->setTokenForFolder(fileId, token);
|
||||
|
||||
FolderMetadata emptyMetadata(accountsState()->account());
|
||||
FolderMetadata emptyMetadata(accountsState()->account());
|
||||
auto encryptedMetadata = emptyMetadata.encryptedMetadata();
|
||||
if (encryptedMetadata.isEmpty()) {
|
||||
//TODO: Mark the folder as unencrypted as the metadata generation failed.
|
||||
@@ -348,36 +339,36 @@ void AccountSettings::slotLockForEncryptionSuccess(const QByteArray& fileId, con
|
||||
return;
|
||||
}
|
||||
auto storeMetadataJob = new StoreMetaDataApiJob(accountsState()->account(), fileId, emptyMetadata.encryptedMetadata());
|
||||
connect(storeMetadataJob, &StoreMetaDataApiJob::success,
|
||||
this, &AccountSettings::slotUploadMetadataSuccess);
|
||||
connect(storeMetadataJob, &StoreMetaDataApiJob::error,
|
||||
this, &AccountSettings::slotUpdateMetadataError);
|
||||
connect(storeMetadataJob, &StoreMetaDataApiJob::success,
|
||||
this, &AccountSettings::slotUploadMetadataSuccess);
|
||||
connect(storeMetadataJob, &StoreMetaDataApiJob::error,
|
||||
this, &AccountSettings::slotUpdateMetadataError);
|
||||
|
||||
storeMetadataJob->start();
|
||||
storeMetadataJob->start();
|
||||
}
|
||||
|
||||
void AccountSettings::slotUploadMetadataSuccess(const QByteArray& folderId)
|
||||
{
|
||||
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
|
||||
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
|
||||
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
|
||||
this, &AccountSettings::slotUnlockFolderSuccess);
|
||||
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
|
||||
this, &AccountSettings::slotUnlockFolderError);
|
||||
unlockJob->start();
|
||||
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
|
||||
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
|
||||
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
|
||||
this, &AccountSettings::slotUnlockFolderSuccess);
|
||||
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
|
||||
this, &AccountSettings::slotUnlockFolderError);
|
||||
unlockJob->start();
|
||||
}
|
||||
|
||||
void AccountSettings::slotUpdateMetadataError(const QByteArray& folderId, int httpReturnCode)
|
||||
{
|
||||
Q_UNUSED(httpReturnCode);
|
||||
|
||||
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
|
||||
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
|
||||
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
|
||||
this, &AccountSettings::slotUnlockFolderSuccess);
|
||||
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
|
||||
this, &AccountSettings::slotUnlockFolderError);
|
||||
unlockJob->start();
|
||||
const auto token = accountsState()->account()->e2e()->tokenForFolder(folderId);
|
||||
auto unlockJob = new UnlockEncryptFolderApiJob(accountsState()->account(), folderId, token);
|
||||
connect(unlockJob, &UnlockEncryptFolderApiJob::success,
|
||||
this, &AccountSettings::slotUnlockFolderSuccess);
|
||||
connect(unlockJob, &UnlockEncryptFolderApiJob::error,
|
||||
this, &AccountSettings::slotUnlockFolderError);
|
||||
unlockJob->start();
|
||||
}
|
||||
|
||||
void AccountSettings::slotLockForEncryptionError(const QByteArray& fileId, int httpErrorCode)
|
||||
@@ -744,7 +735,7 @@ void AccountSettings::slotFolderWizardAccepted()
|
||||
qCInfo(lcAccountSettings) << "Creating folder" << definition.localPath;
|
||||
if (!dir.mkpath(".")) {
|
||||
QMessageBox::warning(this, tr("Folder creation failed"),
|
||||
tr("<p>Could not create local folder <i>%1</i>.")
|
||||
tr("<p>Could not create local folder <i>%1</i>.</p>")
|
||||
.arg(QDir::toNativeSeparators(definition.localPath)));
|
||||
return;
|
||||
}
|
||||
@@ -845,13 +836,16 @@ void AccountSettings::showConnectionLabel(const QString &message, QStringList er
|
||||
"border-width: 1px; border-style: solid; border-color: #aaaaaa;"
|
||||
"border-radius:5px;");
|
||||
if (errors.isEmpty()) {
|
||||
ui->connectLabel->setText(message);
|
||||
QString msg = message;
|
||||
Theme::replaceLinkColorStringBackgroundAware(msg);
|
||||
ui->connectLabel->setText(msg);
|
||||
ui->connectLabel->setToolTip(QString());
|
||||
ui->connectLabel->setStyleSheet(QString());
|
||||
} else {
|
||||
errors.prepend(message);
|
||||
const QString msg = errors.join(QLatin1String("\n"));
|
||||
QString msg = errors.join(QLatin1String("\n"));
|
||||
qCDebug(lcAccountSettings) << msg;
|
||||
Theme::replaceLinkColorStringBackgroundAware(msg, QColor("#bb4d4d"));
|
||||
ui->connectLabel->setText(msg);
|
||||
ui->connectLabel->setToolTip(QString());
|
||||
ui->connectLabel->setStyleSheet(errStyle);
|
||||
@@ -1030,7 +1024,7 @@ void AccountSettings::slotAccountStateChanged()
|
||||
"<a href='%1'>Click here</a> to re-open the browser.")
|
||||
.arg(url.toString(QUrl::FullyEncoded)));
|
||||
} else {
|
||||
showConnectionLabel(tr("Connecting to %1...").arg(serverWithUser));
|
||||
showConnectionLabel(tr("Connecting to %1 …").arg(serverWithUser));
|
||||
}
|
||||
} else {
|
||||
showConnectionLabel(tr("No connection to %1 at %2.")
|
||||
@@ -1252,6 +1246,18 @@ bool AccountSettings::event(QEvent *e)
|
||||
return QWidget::event(e);
|
||||
}
|
||||
|
||||
void AccountSettings::slotStyleChanged()
|
||||
{
|
||||
customizeStyle();
|
||||
}
|
||||
|
||||
void AccountSettings::customizeStyle()
|
||||
{
|
||||
QString msg = ui->connectLabel->text();
|
||||
Theme::replaceLinkColorStringBackgroundAware(msg);
|
||||
ui->connectLabel->setText(msg);
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
#include "accountsettings.moc"
|
||||
|
||||
@@ -63,11 +63,13 @@ signals:
|
||||
void openFolderAlias(const QString &);
|
||||
void showIssuesList(AccountState *account);
|
||||
void requesetMnemonic();
|
||||
void removeAccountFolders(AccountState *account);
|
||||
|
||||
public slots:
|
||||
void slotOpenOC();
|
||||
void slotUpdateQuota(qint64, qint64);
|
||||
void slotAccountStateChanged();
|
||||
void slotStyleChanged();
|
||||
|
||||
AccountState *accountsState() { return _accountState; }
|
||||
|
||||
@@ -128,6 +130,7 @@ private:
|
||||
bool event(QEvent *) override;
|
||||
void createAccountToolbox();
|
||||
void openIgnoredFilesDialog(const QString & absFolderPath);
|
||||
void customizeStyle();
|
||||
|
||||
/// Returns the alias of the selected folder, empty string if none
|
||||
QString selectedFolderAlias() const;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "accountstate.h"
|
||||
#include "accountmanager.h"
|
||||
#include "remotewipe.h"
|
||||
#include "account.h"
|
||||
#include "creds/abstractcredentials.h"
|
||||
#include "creds/httpcredentials.h"
|
||||
@@ -24,6 +25,11 @@
|
||||
#include <QTimer>
|
||||
#include <qfontmetrics.h>
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkRequest>
|
||||
#include <QBuffer>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
Q_LOGGING_CATEGORY(lcAccountState, "nextcloud.gui.account.state", QtInfoMsg)
|
||||
@@ -36,11 +42,12 @@ AccountState::AccountState(AccountPtr account)
|
||||
, _waitingForNewCredentials(false)
|
||||
, _notificationsEtagResponseHeader("*")
|
||||
, _maintenanceToConnectedDelay(60000 + (qrand() % (4 * 60000))) // 1-5min delay
|
||||
, _remoteWipe(new RemoteWipe(_account))
|
||||
{
|
||||
qRegisterMetaType<AccountState *>("AccountState*");
|
||||
|
||||
connect(account.data(), &Account::invalidCredentials,
|
||||
this, &AccountState::slotInvalidCredentials);
|
||||
this, &AccountState::slotHandleRemoteWipeCheck);
|
||||
connect(account.data(), &Account::credentialsFetched,
|
||||
this, &AccountState::slotCredentialsFetched);
|
||||
connect(account.data(), &Account::credentialsAsked,
|
||||
@@ -303,7 +310,7 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
|
||||
break;
|
||||
case ConnectionValidator::CredentialsWrong:
|
||||
case ConnectionValidator::CredentialsNotReady:
|
||||
slotInvalidCredentials();
|
||||
handleInvalidCredentials();
|
||||
break;
|
||||
case ConnectionValidator::SslError:
|
||||
setState(SignedOut);
|
||||
@@ -322,7 +329,20 @@ void AccountState::slotConnectionValidatorResult(ConnectionValidator::Status sta
|
||||
}
|
||||
}
|
||||
|
||||
void AccountState::slotInvalidCredentials()
|
||||
void AccountState::slotHandleRemoteWipeCheck()
|
||||
{
|
||||
// make sure it changes account state and icons
|
||||
signOutByUi();
|
||||
|
||||
qCInfo(lcAccountState) << "Invalid credentials for" << _account->url().toString()
|
||||
<< "checking for remote wipe request";
|
||||
|
||||
_waitingForNewCredentials = false;
|
||||
setState(SignedOut);
|
||||
}
|
||||
|
||||
|
||||
void AccountState::handleInvalidCredentials()
|
||||
{
|
||||
if (isSignedOut() || _waitingForNewCredentials)
|
||||
return;
|
||||
@@ -343,6 +363,7 @@ void AccountState::slotInvalidCredentials()
|
||||
account()->credentials()->askFromUser();
|
||||
}
|
||||
|
||||
|
||||
void AccountState::slotCredentialsFetched(AbstractCredentials *)
|
||||
{
|
||||
// Make a connection attempt, no matter whether the credentials are
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace OCC {
|
||||
|
||||
class AccountState;
|
||||
class Account;
|
||||
class RemoteWipe;
|
||||
|
||||
typedef QExplicitlySharedDataPointer<AccountState> AccountStatePtr;
|
||||
|
||||
@@ -150,6 +151,9 @@ public:
|
||||
*/
|
||||
void setNavigationAppsEtagResponseHeader(const QByteArray &value);
|
||||
|
||||
///Asks for user credentials
|
||||
void handleInvalidCredentials();
|
||||
|
||||
public slots:
|
||||
/// Triggers a ping to the server to update state and
|
||||
/// connection status and errors.
|
||||
@@ -164,7 +168,11 @@ signals:
|
||||
|
||||
protected Q_SLOTS:
|
||||
void slotConnectionValidatorResult(ConnectionValidator::Status status, const QStringList &errors);
|
||||
void slotInvalidCredentials();
|
||||
|
||||
/// When client gets a 401 or 403 checks if server requested remote wipe
|
||||
/// before asking for user credentials again
|
||||
void slotHandleRemoteWipeCheck();
|
||||
|
||||
void slotCredentialsFetched(AbstractCredentials *creds);
|
||||
void slotCredentialsAsked(AbstractCredentials *creds);
|
||||
|
||||
@@ -190,6 +198,13 @@ private:
|
||||
* Milliseconds for which to delay reconnection after 503/maintenance.
|
||||
*/
|
||||
int _maintenanceToConnectedDelay;
|
||||
|
||||
/**
|
||||
* Connects remote wipe check with the account
|
||||
* the log out triggers the check (loads app password -> create request)
|
||||
*/
|
||||
RemoteWipe *_remoteWipe;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace OCC {
|
||||
|
||||
bool operator<(const Activity &rhs, const Activity &lhs)
|
||||
{
|
||||
return rhs._dateTime.toMSecsSinceEpoch() > lhs._dateTime.toMSecsSinceEpoch();
|
||||
return rhs._dateTime > lhs._dateTime;
|
||||
}
|
||||
|
||||
bool operator==(const Activity &rhs, const Activity &lhs)
|
||||
|
||||
@@ -64,20 +64,12 @@ QVariant ActivityListModel::data(const QModelIndex &index, int role) const
|
||||
case ActivityItemDelegate::PathRole:
|
||||
if(!a._file.isEmpty()){
|
||||
auto folder = FolderMan::instance()->folder(a._folder);
|
||||
QString relPath(a._file);
|
||||
if(folder) relPath.prepend(folder->remotePath());
|
||||
list = FolderMan::instance()->findFileInLocalFolders(relPath, ast->account());
|
||||
if (list.count() > 0) {
|
||||
return QVariant(list.at(0));
|
||||
}
|
||||
// File does not exist anymore? Let's try to open its path
|
||||
list = FolderMan::instance()->findFileInLocalFolders(QFileInfo(relPath).path(), ast->account());
|
||||
list = FolderMan::instance()->findFileInLocalFolders(folder->remotePath(), ast->account());
|
||||
if (list.count() > 0) {
|
||||
return QVariant(list.at(0));
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
break;
|
||||
case ActivityItemDelegate::ActionsLinksRole:{
|
||||
QList<QVariant> customList;
|
||||
foreach (ActivityLink customItem, a._links) {
|
||||
@@ -86,7 +78,6 @@ QVariant ActivityListModel::data(const QModelIndex &index, int role) const
|
||||
customList << customVariant;
|
||||
}
|
||||
return customList;
|
||||
break;
|
||||
}
|
||||
case ActivityItemDelegate::ActionIconRole:
|
||||
if(a._type == Activity::NotificationType){
|
||||
@@ -229,6 +220,29 @@ void ActivityListModel::addErrorToActivityList(Activity activity) {
|
||||
combineActivityLists();
|
||||
}
|
||||
|
||||
void ActivityListModel::addIgnoredFileToList(Activity newActivity) {
|
||||
qCInfo(lcActivity) << "First checking for duplicates then add file to the notification list of ignored files: " << newActivity._file;
|
||||
|
||||
bool duplicate = false;
|
||||
if(_listOfIgnoredFiles.size() == 0){
|
||||
_notificationIgnoredFiles = newActivity;
|
||||
_notificationIgnoredFiles._subject = tr("Files from the ignore list as well as symbolic links are not synced. This includes:");
|
||||
_listOfIgnoredFiles.append(newActivity);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach(Activity activity, _listOfIgnoredFiles){
|
||||
if(activity._file == newActivity._file){
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!duplicate){
|
||||
_notificationIgnoredFiles._message.append(", " + newActivity._file);
|
||||
}
|
||||
}
|
||||
|
||||
void ActivityListModel::addNotificationToActivityList(Activity activity) {
|
||||
qCInfo(lcActivity) << "Notification successfully added to the notification list: " << activity._subject;
|
||||
_notificationLists.prepend(activity);
|
||||
@@ -276,22 +290,31 @@ void ActivityListModel::removeActivityFromActivityList(Activity activity) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ActivityListModel::combineActivityLists()
|
||||
{
|
||||
ActivityList resultList;
|
||||
|
||||
std::sort(_notificationErrorsLists.begin(), _notificationErrorsLists.end());
|
||||
resultList.append(_notificationErrorsLists);
|
||||
if(_notificationErrorsLists.count() > 0) {
|
||||
std::sort(_notificationErrorsLists.begin(), _notificationErrorsLists.end());
|
||||
resultList.append(_notificationErrorsLists);
|
||||
}
|
||||
if(_listOfIgnoredFiles.size() > 0)
|
||||
resultList.append(_notificationIgnoredFiles);
|
||||
|
||||
std::sort(_notificationLists.begin(), _notificationLists.end());
|
||||
resultList.append(_notificationLists);
|
||||
if(_notificationLists.count() > 0) {
|
||||
std::sort(_notificationLists.begin(), _notificationLists.end());
|
||||
resultList.append(_notificationLists);
|
||||
}
|
||||
|
||||
std::sort(_syncFileItemLists.begin(), _syncFileItemLists.end());
|
||||
resultList.append(_syncFileItemLists);
|
||||
if(_syncFileItemLists.count() > 0) {
|
||||
std::sort(_syncFileItemLists.begin(), _syncFileItemLists.end());
|
||||
resultList.append(_syncFileItemLists);
|
||||
}
|
||||
|
||||
std::sort(_activityLists.begin(), _activityLists.end());
|
||||
resultList.append(_activityLists);
|
||||
if(_activityLists.count() > 0) {
|
||||
std::sort(_activityLists.begin(), _activityLists.end());
|
||||
resultList.append(_activityLists);
|
||||
}
|
||||
|
||||
beginResetModel();
|
||||
_finalList.clear();
|
||||
|
||||
@@ -51,6 +51,7 @@ public:
|
||||
void addNotificationToActivityList(Activity activity);
|
||||
void clearNotifications();
|
||||
void addErrorToActivityList(Activity activity);
|
||||
void addIgnoredFileToList(Activity newActivity);
|
||||
void addSyncFileItemToActivityList(Activity activity);
|
||||
void removeActivityFromActivityList(int row);
|
||||
void removeActivityFromActivityList(Activity activity);
|
||||
@@ -73,6 +74,8 @@ private:
|
||||
ActivityList _activityLists;
|
||||
ActivityList _syncFileItemLists;
|
||||
ActivityList _notificationLists;
|
||||
ActivityList _listOfIgnoredFiles;
|
||||
Activity _notificationIgnoredFiles;
|
||||
ActivityList _notificationErrorsLists;
|
||||
ActivityList _finalList;
|
||||
AccountState *_accountState;
|
||||
|
||||
@@ -127,11 +127,12 @@ void ActivityWidget::slotProgressInfo(const QString &folder, const ProgressInfo
|
||||
}
|
||||
|
||||
|
||||
if(activity._status == SyncFileItem::FileIgnored && !QFileInfo(f->path() + activity._file).exists()){
|
||||
if(activity._status == SyncFileItem::FileIgnored && !QFileInfo(f->path() + activity._file).exists()) {
|
||||
_model->removeActivityFromActivityList(activity);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if(!QFileInfo(f->path() + activity._file).exists()){
|
||||
_model->removeActivityFromActivityList(activity);
|
||||
continue;
|
||||
@@ -191,8 +192,12 @@ void ActivityWidget::slotItemCompleted(const QString &folder, const SyncFileItem
|
||||
qCWarning(lcActivity) << "Item " << item->_file << " retrieved resulted in error " << item->_errorString;
|
||||
activity._subject = item->_errorString;
|
||||
|
||||
// add 'protocol error' to activity list
|
||||
_model->addErrorToActivityList(activity);
|
||||
if(item->_status == SyncFileItem::Status::FileIgnored) {
|
||||
_model->addIgnoredFileToList(activity);
|
||||
} else {
|
||||
// add 'protocol error' to activity list
|
||||
_model->addErrorToActivityList(activity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,25 +147,31 @@ void WebFlowCredentials::fetchFromKeychain() {
|
||||
}
|
||||
|
||||
void WebFlowCredentials::askFromUser() {
|
||||
// LoginFlowV2 > WebViewFlow > OAuth > Shib > Basic
|
||||
bool useFlow2 = (_account->serverVersionInt() >= Account::makeServerVersion(16, 0, 0));
|
||||
// Determine if the old flow has to be used (GS for now)
|
||||
// Do a DetermineAuthTypeJob to make sure that the server is still using Flow2
|
||||
DetermineAuthTypeJob *job = new DetermineAuthTypeJob(_account->sharedFromThis(), this);
|
||||
connect(job, &DetermineAuthTypeJob::authType, [this](DetermineAuthTypeJob::AuthType type) {
|
||||
// LoginFlowV2 > WebViewFlow > OAuth > Shib > Basic
|
||||
bool useFlow2 = (type != DetermineAuthTypeJob::WebViewFlow);
|
||||
|
||||
_askDialog = new WebFlowCredentialsDialog(_account, useFlow2);
|
||||
_askDialog = new WebFlowCredentialsDialog(_account, useFlow2);
|
||||
|
||||
if (!useFlow2) {
|
||||
QUrl url = _account->url();
|
||||
QString path = url.path() + "/index.php/login/flow";
|
||||
url.setPath(path);
|
||||
_askDialog->setUrl(url);
|
||||
}
|
||||
if (!useFlow2) {
|
||||
QUrl url = _account->url();
|
||||
QString path = url.path() + "/index.php/login/flow";
|
||||
url.setPath(path);
|
||||
_askDialog->setUrl(url);
|
||||
}
|
||||
|
||||
QString msg = tr("You have been logged out of %1 as user %2. Please login again")
|
||||
.arg(_account->displayName(), _user);
|
||||
_askDialog->setInfo(msg);
|
||||
QString msg = tr("You have been logged out of %1 as user %2. Please login again")
|
||||
.arg(_account->displayName(), _user);
|
||||
_askDialog->setInfo(msg);
|
||||
|
||||
_askDialog->show();
|
||||
_askDialog->show();
|
||||
|
||||
connect(_askDialog, &WebFlowCredentialsDialog::urlCatched, this, &WebFlowCredentials::slotAskFromUserCredentialsProvided);
|
||||
connect(_askDialog, &WebFlowCredentialsDialog::urlCatched, this, &WebFlowCredentials::slotAskFromUserCredentialsProvided);
|
||||
});
|
||||
job->start();
|
||||
|
||||
qCDebug(lcWebFlowCredentials()) << "User needs to reauth!";
|
||||
}
|
||||
@@ -240,15 +246,68 @@ void WebFlowCredentials::slotWriteClientCertPEMJobDone()
|
||||
{
|
||||
// write ssl key if there is one
|
||||
if (!_clientSslKey.isNull()) {
|
||||
// Windows workaround: Split the private key into chunks of 2048 bytes,
|
||||
// to allow 4k (4096 bit) keys to be saved (obey Windows's limits)
|
||||
_clientSslKeyChunkBufferPEM = _clientSslKey.toPem();
|
||||
_clientSslKeyChunkCount = 0;
|
||||
|
||||
writeSingleClientKeyChunkPEM(nullptr);
|
||||
} else {
|
||||
// no key, just write credentials
|
||||
slotWriteClientKeyPEMJobDone();
|
||||
}
|
||||
}
|
||||
|
||||
void WebFlowCredentials::writeSingleClientKeyChunkPEM(QKeychain::Job *incomingJob)
|
||||
{
|
||||
// errors?
|
||||
if (incomingJob) {
|
||||
WritePasswordJob *writeJob = static_cast<WritePasswordJob *>(incomingJob);
|
||||
|
||||
if (writeJob->error() != NoError) {
|
||||
qCWarning(lcWebFlowCredentials) << "Error while writing client CA key chunk" << writeJob->errorString();
|
||||
|
||||
_clientSslKeyChunkBufferPEM.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// write a key chunk if there is any in the buffer
|
||||
if (!_clientSslKeyChunkBufferPEM.isEmpty()) {
|
||||
#if defined(Q_OS_WIN)
|
||||
// Windows workaround: Split the private key into chunks of 2048 bytes,
|
||||
// to allow 4k (4096 bit) keys to be saved (obey Windows's limits)
|
||||
auto chunk = _clientSslKeyChunkBufferPEM.left(_clientSslKeyChunkSize);
|
||||
|
||||
_clientSslKeyChunkBufferPEM = _clientSslKeyChunkBufferPEM.right(_clientSslKeyChunkBufferPEM.size() - chunk.size());
|
||||
#else
|
||||
// write full key in one slot on non-Windows, as usual
|
||||
auto chunk = _clientSslKeyChunkBufferPEM;
|
||||
|
||||
_clientSslKeyChunkBufferPEM.clear();
|
||||
#endif
|
||||
auto index = (_clientSslKeyChunkCount++);
|
||||
|
||||
// keep the limit
|
||||
if (_clientSslKeyChunkCount > _clientSslKeyMaxChunks) {
|
||||
qCWarning(lcWebFlowCredentials) << "Maximum client key chunk count exceeded while writing slot" << QString::number(index) << "cutting off after" << QString::number(_clientSslKeyMaxChunks) << "chunks";
|
||||
|
||||
_clientSslKeyChunkBufferPEM.clear();
|
||||
|
||||
slotWriteClientKeyPEMJobDone();
|
||||
return;
|
||||
}
|
||||
|
||||
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
|
||||
addSettingsToJob(_account, job);
|
||||
job->setInsecureFallback(false);
|
||||
connect(job, &Job::finished, this, &WebFlowCredentials::slotWriteClientKeyPEMJobDone);
|
||||
job->setKey(keychainKey(_account->url().toString(), _user + clientKeyPEMC, _account->id()));
|
||||
job->setBinaryData(_clientSslKey.toPem());
|
||||
connect(job, &Job::finished, this, &WebFlowCredentials::writeSingleClientKeyChunkPEM);
|
||||
// only add the key's (sub)"index" after the first element, to stay compatible with older versions and non-Windows
|
||||
job->setKey(keychainKey(_account->url().toString(), _user + clientKeyPEMC + (index > 0 ? (QString(".") + QString::number(index)) : QString()), _account->id()));
|
||||
job->setBinaryData(chunk);
|
||||
job->start();
|
||||
|
||||
chunk.clear();
|
||||
} else {
|
||||
// no key, just write credentials
|
||||
slotWriteClientKeyPEMJobDone();
|
||||
}
|
||||
}
|
||||
@@ -264,7 +323,7 @@ void WebFlowCredentials::writeSingleClientCaCertPEM()
|
||||
|
||||
// keep the limit
|
||||
if (index > (_clientSslCaCertificatesMaxCount - 1)) {
|
||||
qCWarning(lcWebFlowCredentials) << "Maximum client CA cert count exceeded while writing slot" << QString::number(index) << "), cutting off after " << QString::number(_clientSslCaCertificatesMaxCount) << "certs";
|
||||
qCWarning(lcWebFlowCredentials) << "Maximum client CA cert count exceeded while writing slot" << QString::number(index) << "cutting off after" << QString::number(_clientSslCaCertificatesMaxCount) << "certs";
|
||||
|
||||
_clientSslCaCertificatesWriteQueue.clear();
|
||||
|
||||
@@ -358,6 +417,8 @@ void WebFlowCredentials::forgetSensitiveData() {
|
||||
|
||||
fetchUser();
|
||||
|
||||
_account->deleteAppPassword();
|
||||
|
||||
const QString kck = keychainKey(_account->url().toString(), _user, _account->id());
|
||||
if (kck.isEmpty()) {
|
||||
qCDebug(lcWebFlowCredentials()) << "InvalidateToken: User is empty, bailing out!";
|
||||
@@ -371,14 +432,7 @@ void WebFlowCredentials::forgetSensitiveData() {
|
||||
|
||||
invalidateToken();
|
||||
|
||||
/* IMPORTANT
|
||||
* TODO: For "Log out" & "Remove account": Remove client CA certs and KEY!
|
||||
*
|
||||
* Disabled as long as selecting another cert is not supported by the UI.
|
||||
*
|
||||
* Being able to specify a new certificate is important anyway: expiry etc.
|
||||
*/
|
||||
//deleteKeychainEntries();
|
||||
deleteKeychainEntries();
|
||||
}
|
||||
|
||||
void WebFlowCredentials::setAccount(Account *account) {
|
||||
@@ -416,6 +470,9 @@ void WebFlowCredentials::slotFinished(QNetworkReply *reply) {
|
||||
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
_credentialsValid = true;
|
||||
|
||||
/// Used later for remote wipe
|
||||
_account->writeAppPasswordOnce(_password);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,6 +518,9 @@ void WebFlowCredentials::slotReadClientCertPEMJobDone(QKeychain::Job *incomingJo
|
||||
}
|
||||
|
||||
// Load key too
|
||||
_clientSslKeyChunkCount = 0;
|
||||
_clientSslKeyChunkBufferPEM.clear();
|
||||
|
||||
const QString kck = keychainKey(
|
||||
_account->url().toString(),
|
||||
_user + clientKeyPEMC,
|
||||
@@ -476,23 +536,58 @@ void WebFlowCredentials::slotReadClientCertPEMJobDone(QKeychain::Job *incomingJo
|
||||
|
||||
void WebFlowCredentials::slotReadClientKeyPEMJobDone(QKeychain::Job *incomingJob)
|
||||
{
|
||||
// Store key in memory
|
||||
// Errors or next key chunk?
|
||||
ReadPasswordJob *readJob = static_cast<ReadPasswordJob *>(incomingJob);
|
||||
|
||||
if (readJob) {
|
||||
if (readJob->error() == NoError && readJob->binaryData().length() > 0) {
|
||||
QByteArray clientKeyPEM = readJob->binaryData();
|
||||
_clientSslKeyChunkBufferPEM.append(readJob->binaryData());
|
||||
_clientSslKeyChunkCount++;
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
// try to fetch next chunk
|
||||
if (_clientSslKeyChunkCount < _clientSslKeyMaxChunks) {
|
||||
const QString kck = keychainKey(
|
||||
_account->url().toString(),
|
||||
_user + clientKeyPEMC + QString(".") + QString::number(_clientSslKeyChunkCount),
|
||||
_keychainMigration ? QString() : _account->id());
|
||||
|
||||
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
|
||||
addSettingsToJob(_account, job);
|
||||
job->setInsecureFallback(false);
|
||||
job->setKey(kck);
|
||||
connect(job, &Job::finished, this, &WebFlowCredentials::slotReadClientKeyPEMJobDone);
|
||||
job->start();
|
||||
|
||||
return;
|
||||
} else {
|
||||
qCWarning(lcWebFlowCredentials) << "Maximum client key chunk count reached, ignoring after" << _clientSslKeyMaxChunks;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
if (readJob->error() != QKeychain::Error::EntryNotFound ||
|
||||
((readJob->error() == QKeychain::Error::EntryNotFound) && _clientSslKeyChunkCount == 0)) {
|
||||
qCWarning(lcWebFlowCredentials) << "Unable to read client key chunk slot" << QString::number(_clientSslKeyChunkCount) << readJob->errorString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Store key in memory
|
||||
if (_clientSslKeyChunkBufferPEM.size() > 0) {
|
||||
// FIXME Unfortunately Qt has a bug and we can't just use QSsl::Opaque to let it
|
||||
// load whatever we have. So we try until it works.
|
||||
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Rsa);
|
||||
_clientSslKey = QSslKey(_clientSslKeyChunkBufferPEM, QSsl::Rsa);
|
||||
if (_clientSslKey.isNull()) {
|
||||
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Dsa);
|
||||
_clientSslKey = QSslKey(_clientSslKeyChunkBufferPEM, QSsl::Dsa);
|
||||
}
|
||||
if (_clientSslKey.isNull()) {
|
||||
_clientSslKey = QSslKey(clientKeyPEM, QSsl::Ec);
|
||||
_clientSslKey = QSslKey(_clientSslKeyChunkBufferPEM, QSsl::Ec);
|
||||
}
|
||||
if (_clientSslKey.isNull()) {
|
||||
qCWarning(lcWebFlowCredentials) << "Could not load SSL key into Qt!";
|
||||
}
|
||||
// clear key chunk buffer, but don't set _clientSslKeyChunkCount to zero because we need it for deleteKeychainEntries
|
||||
_clientSslKeyChunkBufferPEM.clear();
|
||||
}
|
||||
|
||||
// Start fetching client CA certs
|
||||
@@ -517,7 +612,7 @@ void WebFlowCredentials::readSingleClientCaCertPEM()
|
||||
connect(job, &Job::finished, this, &WebFlowCredentials::slotReadClientCaCertsPEMJobDone);
|
||||
job->start();
|
||||
} else {
|
||||
qCWarning(lcWebFlowCredentials) << "Maximum client CA cert count exceeded while reading, ignoring after " << _clientSslCaCertificatesMaxCount;
|
||||
qCWarning(lcWebFlowCredentials) << "Maximum client CA cert count exceeded while reading, ignoring after" << _clientSslCaCertificatesMaxCount;
|
||||
|
||||
slotReadClientCaCertsPEMJobDone(nullptr);
|
||||
}
|
||||
@@ -540,7 +635,7 @@ void WebFlowCredentials::slotReadClientCaCertsPEMJobDone(QKeychain::Job *incomin
|
||||
} else {
|
||||
if (readJob->error() != QKeychain::Error::EntryNotFound ||
|
||||
((readJob->error() == QKeychain::Error::EntryNotFound) && _clientSslCaCertificates.count() == 0)) {
|
||||
qCWarning(lcWebFlowCredentials) << "Unable to read client CA cert slot " << QString::number(_clientSslCaCertificates.count()) << readJob->errorString();
|
||||
qCWarning(lcWebFlowCredentials) << "Unable to read client CA cert slot" << QString::number(_clientSslCaCertificates.count()) << readJob->errorString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -596,7 +691,7 @@ void WebFlowCredentials::deleteKeychainEntries(bool oldKeychainEntries) {
|
||||
auto startDeleteJob = [this, oldKeychainEntries](QString user) {
|
||||
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
|
||||
addSettingsToJob(_account, job);
|
||||
job->setInsecureFallback(true);
|
||||
job->setInsecureFallback(false);
|
||||
job->setKey(keychainKey(_account->url().toString(),
|
||||
user,
|
||||
oldKeychainEntries ? QString() : _account->id()));
|
||||
@@ -604,12 +699,34 @@ void WebFlowCredentials::deleteKeychainEntries(bool oldKeychainEntries) {
|
||||
};
|
||||
|
||||
startDeleteJob(_user);
|
||||
startDeleteJob(_user + clientKeyPEMC);
|
||||
startDeleteJob(_user + clientCertificatePEMC);
|
||||
|
||||
for (auto i = 0; i < _clientSslCaCertificates.count(); i++) {
|
||||
startDeleteJob(_user + clientCaCertificatePEMC + QString::number(i));
|
||||
/* IMPORTANT - remove later - FIXME MS@2019-12-07 -->
|
||||
* TODO: For "Log out" & "Remove account": Remove client CA certs and KEY!
|
||||
*
|
||||
* Disabled as long as selecting another cert is not supported by the UI.
|
||||
*
|
||||
* Being able to specify a new certificate is important anyway: expiry etc.
|
||||
*
|
||||
* We introduce this dirty hack here, to allow deleting them upon Remote Wipe.
|
||||
*/
|
||||
if(_account->isRemoteWipeRequested_HACK()) {
|
||||
// <-- FIXME MS@2019-12-07
|
||||
startDeleteJob(_user + clientKeyPEMC);
|
||||
startDeleteJob(_user + clientCertificatePEMC);
|
||||
|
||||
for (auto i = 0; i < _clientSslCaCertificates.count(); i++) {
|
||||
startDeleteJob(_user + clientCaCertificatePEMC + QString::number(i));
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
// also delete key sub-chunks (Windows workaround)
|
||||
for (auto i = 1; i < _clientSslKeyChunkCount; i++) {
|
||||
startDeleteJob(_user + clientKeyPEMC + QString(".") + QString::number(i));
|
||||
}
|
||||
#endif
|
||||
// FIXME MS@2019-12-07 -->
|
||||
}
|
||||
// <-- FIXME MS@2019-12-07
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ private:
|
||||
void writeSingleClientCaCertPEM();
|
||||
|
||||
/*
|
||||
* Since we're limited by Windows limits we just create our own
|
||||
* Since we're limited by Windows limits, we just create our own
|
||||
* limit to avoid evil things happening by endless recursion
|
||||
*
|
||||
* Better than storing the count and relying on maybe-hacked values
|
||||
@@ -91,6 +91,19 @@ private:
|
||||
static constexpr int _clientSslCaCertificatesMaxCount = 10;
|
||||
QQueue<QSslCertificate> _clientSslCaCertificatesWriteQueue;
|
||||
|
||||
/*
|
||||
* Workaround: ...and this time only on Windows:
|
||||
*
|
||||
* Split the private key into chunks of 2048 bytes,
|
||||
* to allow 4k (4096 bit) keys to be saved (see limits above)
|
||||
*/
|
||||
void writeSingleClientKeyChunkPEM(QKeychain::Job *incomingJob);
|
||||
|
||||
static constexpr int _clientSslKeyChunkSize = 2048;
|
||||
static constexpr int _clientSslKeyMaxChunks = 10;
|
||||
int _clientSslKeyChunkCount = 0;
|
||||
QByteArray _clientSslKeyChunkBufferPEM;
|
||||
|
||||
protected:
|
||||
/** Reads data from keychain locations
|
||||
*
|
||||
|
||||
@@ -902,13 +902,19 @@ void Folder::slotItemCompleted(const SyncFileItemPtr &item)
|
||||
}
|
||||
|
||||
// add new directories or remove gone away dirs to the watcher
|
||||
if (item->isDirectory() && item->_instruction == CSYNC_INSTRUCTION_NEW) {
|
||||
if (_folderWatcher)
|
||||
_folderWatcher->addPath(path() + item->_file);
|
||||
}
|
||||
if (item->isDirectory() && item->_instruction == CSYNC_INSTRUCTION_REMOVE) {
|
||||
if (_folderWatcher)
|
||||
_folderWatcher->removePath(path() + item->_file);
|
||||
if (_folderWatcher && item->isDirectory()) {
|
||||
switch (item->_instruction) {
|
||||
case CSYNC_INSTRUCTION_NEW:
|
||||
_folderWatcher->addPath(path() + item->_file);
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_REMOVE:
|
||||
_folderWatcher->removePath(path() + item->_file);
|
||||
break;
|
||||
case CSYNC_INSTRUCTION_RENAME:
|
||||
_folderWatcher->removePath(path() + item->_file);
|
||||
_folderWatcher->addPath(path() + item->destination());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Success and failure of sync items adjust what the next sync is
|
||||
|
||||
@@ -75,7 +75,7 @@ FolderMan::FolderMan(QObject *parent)
|
||||
this, &FolderMan::slotScheduleFolderByTime);
|
||||
_timeScheduler.start();
|
||||
|
||||
connect(AccountManager::instance(), &AccountManager::accountRemoved,
|
||||
connect(AccountManager::instance(), &AccountManager::removeAccountFolders,
|
||||
this, &FolderMan::slotRemoveFoldersForAccount);
|
||||
|
||||
connect(_lockWatcher.data(), &LockWatcher::fileUnlocked,
|
||||
@@ -443,7 +443,7 @@ void FolderMan::slotFolderSyncPaused(Folder *f, bool paused)
|
||||
void FolderMan::slotFolderCanSyncChanged()
|
||||
{
|
||||
Folder *f = qobject_cast<Folder *>(sender());
|
||||
ASSERT(f);
|
||||
ASSERT(f);
|
||||
if (f->canSync()) {
|
||||
_socketApi->slotRegisterPath(f->alias());
|
||||
} else {
|
||||
@@ -1084,6 +1084,73 @@ bool FolderMan::startFromScratch(const QString &localFolder)
|
||||
return true;
|
||||
}
|
||||
|
||||
void FolderMan::slotWipeFolderForAccount(AccountState *accountState)
|
||||
{
|
||||
QVarLengthArray<Folder *, 16> foldersToRemove;
|
||||
Folder::MapIterator i(_folderMap);
|
||||
while (i.hasNext()) {
|
||||
i.next();
|
||||
Folder *folder = i.value();
|
||||
if (folder->accountState() == accountState) {
|
||||
foldersToRemove.append(folder);
|
||||
}
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
foreach (const auto &f, foldersToRemove) {
|
||||
if (!f) {
|
||||
qCCritical(lcFolderMan) << "Can not remove null folder";
|
||||
return;
|
||||
}
|
||||
|
||||
qCInfo(lcFolderMan) << "Removing " << f->alias();
|
||||
|
||||
const bool currentlyRunning = (_currentSyncFolder == f);
|
||||
if (currentlyRunning) {
|
||||
// abort the sync now
|
||||
terminateSyncProcess();
|
||||
}
|
||||
|
||||
if (_scheduledFolders.removeAll(f) > 0) {
|
||||
emit scheduleQueueChanged();
|
||||
}
|
||||
|
||||
// wipe database
|
||||
f->wipe();
|
||||
|
||||
// wipe data
|
||||
QDir userFolder(f->path());
|
||||
if (userFolder.exists()) {
|
||||
success = userFolder.removeRecursively();
|
||||
if (!success) {
|
||||
qCWarning(lcFolderMan) << "Failed to remove existing folder " << f->path();
|
||||
} else {
|
||||
qCInfo(lcFolderMan) << "wipe: Removed file " << f->path();
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
success = true;
|
||||
qCWarning(lcFolderMan) << "folder does not exist, can not remove.";
|
||||
}
|
||||
|
||||
f->setSyncPaused(true);
|
||||
|
||||
// remove the folder configuration
|
||||
f->removeFromSettings();
|
||||
|
||||
unloadFolder(f);
|
||||
if (currentlyRunning) {
|
||||
delete f;
|
||||
}
|
||||
|
||||
_navigationPaneHelper.scheduleUpdateCloudStorageRegistry();
|
||||
}
|
||||
|
||||
emit folderListChanged(_folderMap);
|
||||
emit wipeDone(accountState, success);
|
||||
}
|
||||
|
||||
void FolderMan::setDirtyProxy()
|
||||
{
|
||||
foreach (Folder *f, _folderMap.values()) {
|
||||
|
||||
@@ -207,6 +207,11 @@ signals:
|
||||
*/
|
||||
void folderListChanged(const Folder::Map &);
|
||||
|
||||
/**
|
||||
* Emitted once slotRemoveFoldersForAccount is done wiping
|
||||
*/
|
||||
void wipeDone(AccountState *account, bool success);
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
@@ -231,6 +236,9 @@ public slots:
|
||||
// slot to schedule an ETag job (from Folder only)
|
||||
void slotScheduleETagJob(const QString &alias, RequestEtagJob *job);
|
||||
|
||||
/** Wipe folder */
|
||||
void slotWipeFolderForAccount(AccountState *accountState);
|
||||
|
||||
private slots:
|
||||
void slotFolderSyncPaused(Folder *, bool paused);
|
||||
void slotFolderCanSyncChanged();
|
||||
|
||||
@@ -186,7 +186,7 @@ QVariant FolderStatusModel::data(const QModelIndex &index, int role) const
|
||||
return QVariant(tr("Error while loading the list of folders from the server.")
|
||||
+ QString("\n") + x->_lastErrorString);
|
||||
} else {
|
||||
return tr("Fetching folder list from server...");
|
||||
return tr("Fetching folder list from server …");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1099,15 +1099,15 @@ void FolderStatusModel::slotFolderSyncStateChange(Folder *f)
|
||||
}
|
||||
QString message;
|
||||
if (pos <= 0) {
|
||||
message = tr("Waiting...");
|
||||
message = tr("Waiting …");
|
||||
} else {
|
||||
message = tr("Waiting for %n other folder(s)...", "", pos);
|
||||
message = tr("Waiting for %n other folder(s) …", "", pos);
|
||||
}
|
||||
pi = SubFolderInfo::Progress();
|
||||
pi._overallSyncString = message;
|
||||
} else if (state == SyncResult::SyncPrepare) {
|
||||
pi = SubFolderInfo::Progress();
|
||||
pi._overallSyncString = tr("Preparing to sync...");
|
||||
pi._overallSyncString = tr("Preparing to sync …");
|
||||
} else if (state == SyncResult::Problem || state == SyncResult::Success) {
|
||||
// Reset the progress info after a sync.
|
||||
pi = SubFolderInfo::Progress();
|
||||
|
||||
@@ -57,6 +57,13 @@ GeneralSettings::GeneralSettings(QWidget *parent)
|
||||
|
||||
connect(_ui->showInExplorerNavigationPaneCheckBox, &QAbstractButton::toggled, this, &GeneralSettings::slotShowInExplorerNavigationPane);
|
||||
|
||||
// Rename 'Explorer' appropriately on non-Windows
|
||||
#ifdef Q_OS_MAC
|
||||
QString txt = _ui->showInExplorerNavigationPaneCheckBox->text();
|
||||
txt.replace(QString::fromLatin1("Explorer"), QString::fromLatin1("Finder"));
|
||||
_ui->showInExplorerNavigationPaneCheckBox->setText(txt);
|
||||
#endif
|
||||
|
||||
_ui->autostartCheckBox->setChecked(Utility::hasLaunchOnStartup(Theme::instance()->appName()));
|
||||
connect(_ui->autostartCheckBox, &QAbstractButton::toggled, this, &GeneralSettings::slotToggleLaunchOnStartup);
|
||||
|
||||
@@ -70,7 +77,8 @@ GeneralSettings::GeneralSettings(QWidget *parent)
|
||||
connect(_ui->legalNoticeButton, &QPushButton::clicked, this, &GeneralSettings::slotShowLegalNotice);
|
||||
|
||||
loadMiscSettings();
|
||||
slotUpdateInfo();
|
||||
// updater info now set in: customizeStyle
|
||||
//slotUpdateInfo();
|
||||
|
||||
// misc
|
||||
connect(_ui->monoIconsCheckBox, &QAbstractButton::toggled, this, &GeneralSettings::saveMiscSettings);
|
||||
@@ -109,6 +117,8 @@ GeneralSettings::GeneralSettings(QWidget *parent)
|
||||
|
||||
// accountAdded means the wizard was finished and the wizard might change some options.
|
||||
connect(AccountManager::instance(), &AccountManager::accountAdded, this, &GeneralSettings::loadMiscSettings);
|
||||
|
||||
customizeStyle();
|
||||
}
|
||||
|
||||
GeneralSettings::~GeneralSettings()
|
||||
@@ -149,7 +159,11 @@ void GeneralSettings::slotUpdateInfo()
|
||||
connect(updater, &OCUpdater::downloadStateChanged, this, &GeneralSettings::slotUpdateInfo, Qt::UniqueConnection);
|
||||
connect(_ui->restartButton, &QAbstractButton::clicked, updater, &OCUpdater::slotStartInstaller, Qt::UniqueConnection);
|
||||
connect(_ui->restartButton, &QAbstractButton::clicked, qApp, &QApplication::quit, Qt::UniqueConnection);
|
||||
_ui->updateStateLabel->setText(updater->statusString());
|
||||
|
||||
QString status = updater->statusString();
|
||||
Theme::replaceLinkColorStringBackgroundAware(status);
|
||||
_ui->updateStateLabel->setText(status);
|
||||
|
||||
_ui->restartButton->setVisible(updater->downloadState() == OCUpdater::DownloadComplete);
|
||||
} else {
|
||||
// can't have those infos from sparkle currently
|
||||
@@ -211,4 +225,20 @@ void GeneralSettings::slotShowLegalNotice()
|
||||
delete notice;
|
||||
}
|
||||
|
||||
void GeneralSettings::slotStyleChanged()
|
||||
{
|
||||
customizeStyle();
|
||||
}
|
||||
|
||||
void GeneralSettings::customizeStyle()
|
||||
{
|
||||
// setup about section
|
||||
QString about = Theme::instance()->about();
|
||||
Theme::replaceLinkColorStringBackgroundAware(about);
|
||||
_ui->aboutLabel->setText(about);
|
||||
|
||||
// updater info
|
||||
slotUpdateInfo();
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
@@ -39,6 +39,9 @@ public:
|
||||
~GeneralSettings();
|
||||
QSize sizeHint() const override;
|
||||
|
||||
public slots:
|
||||
void slotStyleChanged();
|
||||
|
||||
private slots:
|
||||
void saveMiscSettings();
|
||||
void slotToggleLaunchOnStartup(bool);
|
||||
@@ -50,6 +53,8 @@ private slots:
|
||||
void slotShowLegalNotice();
|
||||
|
||||
private:
|
||||
void customizeStyle();
|
||||
|
||||
Ui::GeneralSettings *_ui;
|
||||
QPointer<IgnoreListEditor> _ignoreEditor;
|
||||
QPointer<SyncLogDialog> _syncLogDialog;
|
||||
|
||||
@@ -24,7 +24,7 @@ LegalNotice::LegalNotice(QDialog *parent)
|
||||
{
|
||||
_ui->setupUi(this);
|
||||
|
||||
QString notice = tr("<p>Copyright 2017-2018 Nextcloud GmbH<br />"
|
||||
QString notice = tr("<p>Copyright 2017-2019 Nextcloud GmbH<br />"
|
||||
"Copyright 2012-2018 ownCloud GmbH</p>");
|
||||
|
||||
notice += tr("<p>Licensed under the GNU General Public License (GPL) Version 2.0 or any later version.</p>");
|
||||
|
||||
@@ -20,12 +20,7 @@
|
||||
#include "progressdispatcher.h"
|
||||
#include "owncloudsetupwizard.h"
|
||||
#include "sharedialog.h"
|
||||
#if defined(Q_OS_MAC)
|
||||
#include "settingsdialogmac.h"
|
||||
#include "macwindow.h" // qtmacgoodies
|
||||
#else
|
||||
#include "settingsdialog.h"
|
||||
#endif
|
||||
#include "logger.h"
|
||||
#include "logbrowser.h"
|
||||
#include "account.h"
|
||||
@@ -62,11 +57,7 @@ const char propertyAccountC[] = "oc_account";
|
||||
ownCloudGui::ownCloudGui(Application *parent)
|
||||
: QObject(parent)
|
||||
, _tray(nullptr)
|
||||
#if defined(Q_OS_MAC)
|
||||
, _settingsDialog(new SettingsDialogMac(this))
|
||||
#else
|
||||
, _settingsDialog(new SettingsDialog(this))
|
||||
#endif
|
||||
, _logBrowser(nullptr)
|
||||
#ifdef WITH_LIBCLOUDPROVIDERS
|
||||
, _bus(QDBusConnection::sessionBus())
|
||||
@@ -421,7 +412,7 @@ void ownCloudGui::addAccountContextMenu(AccountStatePtr accountState, QMenu *men
|
||||
}
|
||||
|
||||
if (accountState->isSignedOut()) {
|
||||
QAction *signin = menu->addAction(tr("Log in..."));
|
||||
QAction *signin = menu->addAction(tr("Log in …"));
|
||||
signin->setProperty(propertyAccountC, QVariant::fromValue(accountState));
|
||||
connect(signin, &QAction::triggered, this, &ownCloudGui::slotLogin);
|
||||
} else {
|
||||
@@ -786,9 +777,9 @@ void ownCloudGui::setupActions()
|
||||
_actionStatus->setEnabled(false);
|
||||
_navLinksMenu = new QMenu(tr("Apps"));
|
||||
_navLinksMenu->setEnabled(false);
|
||||
_actionSettings = new QAction(tr("Settings..."), this);
|
||||
_actionNewAccountWizard = new QAction(tr("New account..."), this);
|
||||
_actionRecent = new QAction(tr("View more activity..."), this);
|
||||
_actionSettings = new QAction(tr("Settings …"), this);
|
||||
_actionNewAccountWizard = new QAction(tr("New account …"), this);
|
||||
_actionRecent = new QAction(tr("View more activity …"), this);
|
||||
_actionRecent->setEnabled(true);
|
||||
|
||||
QObject::connect(_actionRecent, &QAction::triggered, this, &ownCloudGui::slotShowSyncProtocol);
|
||||
@@ -827,6 +818,10 @@ void ownCloudGui::fetchNavigationApps(AccountStatePtr account){
|
||||
|
||||
void ownCloudGui::buildNavigationAppsMenu(AccountStatePtr account, QMenu *accountMenu){
|
||||
auto navLinks = _navApps.value(account);
|
||||
|
||||
_navLinksMenu->clear();
|
||||
_navLinksMenu->setEnabled(navLinks.size() > 0);
|
||||
|
||||
if(navLinks.size() > 0){
|
||||
// when there is only one account add the nav links above the settings
|
||||
QAction *actionBefore = _actionSettings;
|
||||
@@ -853,7 +848,6 @@ void ownCloudGui::buildNavigationAppsMenu(AccountStatePtr account, QMenu *accoun
|
||||
connect(action, &QAction::triggered, this, [href] { QDesktopServices::openUrl(href); });
|
||||
_navLinksMenu->addAction(action);
|
||||
}
|
||||
_navLinksMenu->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -940,7 +934,7 @@ void ownCloudGui::slotUpdateProgress(const QString &folder, const ProgressInfo &
|
||||
quint64 totalFileCount = qMax(progress.totalFiles(), currentFile);
|
||||
QString msg;
|
||||
if (progress.trustEta()) {
|
||||
msg = tr("Syncing %1 of %2 (%3 left)")
|
||||
msg = tr("Syncing %1 of %2 (%3 left)")
|
||||
.arg(currentFile)
|
||||
.arg(totalFileCount)
|
||||
.arg(Utility::durationToDescriptiveString2(progress.totalProgress().estimatedEta));
|
||||
@@ -1074,12 +1068,7 @@ void ownCloudGui::slotShowGuiMessage(const QString &title, const QString &messag
|
||||
void ownCloudGui::slotShowSettings()
|
||||
{
|
||||
if (_settingsDialog.isNull()) {
|
||||
_settingsDialog =
|
||||
#if defined(Q_OS_MAC)
|
||||
new SettingsDialogMac(this);
|
||||
#else
|
||||
new SettingsDialog(this);
|
||||
#endif
|
||||
_settingsDialog = new SettingsDialog(this);
|
||||
_settingsDialog->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
_settingsDialog->show();
|
||||
}
|
||||
@@ -1140,10 +1129,6 @@ void ownCloudGui::raiseDialog(QWidget *raiseWidget)
|
||||
raiseWidget->raise();
|
||||
raiseWidget->activateWindow();
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
// viel hilft viel ;-)
|
||||
MacWindow::bringToFront(raiseWidget);
|
||||
#endif
|
||||
#if defined(Q_OS_X11)
|
||||
WId wid = widget->winId();
|
||||
NETWM::init();
|
||||
|
||||
@@ -34,7 +34,6 @@ namespace OCC {
|
||||
class Folder;
|
||||
|
||||
class SettingsDialog;
|
||||
class SettingsDialogMac;
|
||||
class ShareDialog;
|
||||
class Application;
|
||||
class LogBrowser;
|
||||
@@ -131,11 +130,7 @@ private:
|
||||
void buildNavigationAppsMenu(AccountStatePtr account, QMenu *accountMenu);
|
||||
|
||||
QPointer<Systray> _tray;
|
||||
#if defined(Q_OS_MAC)
|
||||
QPointer<SettingsDialogMac> _settingsDialog;
|
||||
#else
|
||||
QPointer<SettingsDialog> _settingsDialog;
|
||||
#endif
|
||||
QPointer<LogBrowser> _logBrowser;
|
||||
// tray's menu
|
||||
QScopedPointer<QMenu> _contextMenu;
|
||||
|
||||
@@ -331,7 +331,7 @@ void OwncloudSetupWizard::slotConnectToOCUrl(const QString &url)
|
||||
AbstractCredentials *creds = _ocWizard->getCredentials();
|
||||
_ocWizard->account()->setCredentials(creds);
|
||||
_ocWizard->setField(QLatin1String("OCUrl"), url);
|
||||
_ocWizard->appendToConfigurationLog(tr("Trying to connect to %1 at %2...")
|
||||
_ocWizard->appendToConfigurationLog(tr("Trying to connect to %1 at %2 …")
|
||||
.arg(Theme::instance()->appNameGUI())
|
||||
.arg(url));
|
||||
|
||||
@@ -452,7 +452,7 @@ void OwncloudSetupWizard::slotCreateLocalAndRemoteFolders(const QString &localFo
|
||||
tr("Local sync folder %1 already exists, setting it up for sync.<br/><br/>")
|
||||
.arg(Utility::escape(localFolder)));
|
||||
} else {
|
||||
QString res = tr("Creating local sync folder %1...").arg(localFolder);
|
||||
QString res = tr("Creating local sync folder %1 …").arg(localFolder);
|
||||
if (fi.mkpath(localFolder)) {
|
||||
FileSystem::setFolderMinimumPermissions(localFolder);
|
||||
Utility::setupFavLink(localFolder);
|
||||
|
||||
173
src/gui/remotewipe.cpp
Normal file
173
src/gui/remotewipe.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (C) by Camila Ayres <hello@camila.codes>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "remotewipe.h"
|
||||
#include "folderman.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QNetworkRequest>
|
||||
#include <QBuffer>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
Q_LOGGING_CATEGORY(lcRemoteWipe, "nextcloud.gui.remotewipe", QtInfoMsg)
|
||||
|
||||
RemoteWipe::RemoteWipe(AccountPtr account, QObject *parent)
|
||||
: _account(account),
|
||||
_appPassword(QString()),
|
||||
_accountRemoved(false),
|
||||
_networkManager(nullptr),
|
||||
_networkReplyCheck(nullptr),
|
||||
_networkReplySuccess(nullptr)
|
||||
{
|
||||
QObject::connect(AccountManager::instance(), &AccountManager::accountRemoved,
|
||||
this, [=](AccountState *) {
|
||||
_accountRemoved = true;
|
||||
});
|
||||
QObject::connect(this, &RemoteWipe::authorized, FolderMan::instance(),
|
||||
&FolderMan::slotWipeFolderForAccount);
|
||||
QObject::connect(FolderMan::instance(), &FolderMan::wipeDone, this,
|
||||
&RemoteWipe::notifyServerSuccessJob);
|
||||
QObject::connect(_account.data(), &Account::appPasswordRetrieved, this,
|
||||
&RemoteWipe::startCheckJobWithAppPassword);
|
||||
}
|
||||
|
||||
void RemoteWipe::startCheckJobWithAppPassword(QString pwd){
|
||||
if(pwd.isEmpty())
|
||||
return;
|
||||
|
||||
_appPassword = pwd;
|
||||
QUrl requestUrl = Utility::concatUrlPath(_account->url().toString(),
|
||||
QLatin1String("/index.php/core/wipe/check"));
|
||||
QNetworkRequest request;
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader,
|
||||
"application/x-www-form-urlencoded");
|
||||
request.setUrl(requestUrl);
|
||||
request.setSslConfiguration(_account->getOrCreateSslConfig());
|
||||
auto requestBody = new QBuffer;
|
||||
QUrlQuery arguments(QString("token=%1").arg(_appPassword));
|
||||
requestBody->setData(arguments.query(QUrl::FullyEncoded).toLatin1());
|
||||
_networkReplyCheck = _networkManager.post(request, requestBody);
|
||||
QObject::connect(&_networkManager, SIGNAL(sslErrors(QNetworkReply *, QList<QSslError>)),
|
||||
_account.data(), SLOT(slotHandleSslErrors(QNetworkReply *, QList<QSslError>)));
|
||||
QObject::connect(_networkReplyCheck, &QNetworkReply::finished, this,
|
||||
&RemoteWipe::checkJobSlot);
|
||||
}
|
||||
|
||||
void RemoteWipe::checkJobSlot()
|
||||
{
|
||||
auto jsonData = _networkReplyCheck->readAll();
|
||||
QJsonParseError jsonParseError;
|
||||
QJsonObject json = QJsonDocument::fromJson(jsonData, &jsonParseError).object();
|
||||
bool wipe = false;
|
||||
|
||||
//check for errors
|
||||
if (_networkReplyCheck->error() != QNetworkReply::NoError ||
|
||||
jsonParseError.error != QJsonParseError::NoError) {
|
||||
QString errorReason;
|
||||
QString errorFromJson = json["error"].toString();
|
||||
if (!errorFromJson.isEmpty()) {
|
||||
qCWarning(lcRemoteWipe) << QString("Error returned from the server: <em>%1<em>")
|
||||
.arg(errorFromJson.toHtmlEscaped());
|
||||
} else if (_networkReplyCheck->error() != QNetworkReply::NoError) {
|
||||
qCWarning(lcRemoteWipe) << QString("There was an error accessing the 'token' endpoint: <br><em>%1</em>")
|
||||
.arg(_networkReplyCheck->errorString().toHtmlEscaped());
|
||||
} else if (jsonParseError.error != QJsonParseError::NoError) {
|
||||
qCWarning(lcRemoteWipe) << QString("Could not parse the JSON returned from the server: <br><em>%1</em>")
|
||||
.arg(jsonParseError.errorString());
|
||||
} else {
|
||||
qCWarning(lcRemoteWipe) << QString("The reply from the server did not contain all expected fields");
|
||||
}
|
||||
|
||||
// check for wipe request
|
||||
} else if(!json.value("wipe").isUndefined()){
|
||||
wipe = json["wipe"].toBool();
|
||||
}
|
||||
|
||||
auto manager = AccountManager::instance();
|
||||
auto accountState = manager->account(_account->displayName()).data();
|
||||
|
||||
if(wipe){
|
||||
/* IMPORTANT - remove later - FIXME MS@2019-12-07 -->
|
||||
* TODO: For "Log out" & "Remove account": Remove client CA certs and KEY!
|
||||
*
|
||||
* Disabled as long as selecting another cert is not supported by the UI.
|
||||
*
|
||||
* Being able to specify a new certificate is important anyway: expiry etc.
|
||||
*
|
||||
* We introduce this dirty hack here, to allow deleting them upon Remote Wipe.
|
||||
*/
|
||||
_account->setRemoteWipeRequested_HACK();
|
||||
// <-- FIXME MS@2019-12-07
|
||||
|
||||
// delete account
|
||||
manager->deleteAccount(accountState);
|
||||
manager->save();
|
||||
|
||||
// delete data
|
||||
emit authorized(accountState);
|
||||
|
||||
} else {
|
||||
// ask user for his credentials again
|
||||
accountState->handleInvalidCredentials();
|
||||
}
|
||||
|
||||
_networkReplyCheck->deleteLater();
|
||||
}
|
||||
|
||||
void RemoteWipe::notifyServerSuccessJob(AccountState *accountState, bool dataWiped){
|
||||
if(_accountRemoved && dataWiped && _account == accountState->account()){
|
||||
QUrl requestUrl = Utility::concatUrlPath(_account->url().toString(),
|
||||
QLatin1String("/index.php/core/wipe/success"));
|
||||
QNetworkRequest request;
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader,
|
||||
"application/x-www-form-urlencoded");
|
||||
request.setUrl(requestUrl);
|
||||
request.setSslConfiguration(_account->getOrCreateSslConfig());
|
||||
auto requestBody = new QBuffer;
|
||||
QUrlQuery arguments(QString("token=%1").arg(_appPassword));
|
||||
requestBody->setData(arguments.query(QUrl::FullyEncoded).toLatin1());
|
||||
_networkReplySuccess = _networkManager.post(request, requestBody);
|
||||
QObject::connect(_networkReplySuccess, &QNetworkReply::finished, this,
|
||||
&RemoteWipe::notifyServerSuccessJobSlot);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteWipe::notifyServerSuccessJobSlot()
|
||||
{
|
||||
auto jsonData = _networkReplySuccess->readAll();
|
||||
QJsonParseError jsonParseError;
|
||||
QJsonObject json = QJsonDocument::fromJson(jsonData, &jsonParseError).object();
|
||||
if (_networkReplySuccess->error() != QNetworkReply::NoError ||
|
||||
jsonParseError.error != QJsonParseError::NoError) {
|
||||
QString errorReason;
|
||||
QString errorFromJson = json["error"].toString();
|
||||
if (!errorFromJson.isEmpty()) {
|
||||
qCWarning(lcRemoteWipe) << QString("Error returned from the server: <em>%1</em>")
|
||||
.arg(errorFromJson.toHtmlEscaped());
|
||||
} else if (_networkReplySuccess->error() != QNetworkReply::NoError) {
|
||||
qCWarning(lcRemoteWipe) << QString("There was an error accessing the 'success' endpoint: <br><em>%1</em>")
|
||||
.arg(_networkReplySuccess->errorString().toHtmlEscaped());
|
||||
} else if (jsonParseError.error != QJsonParseError::NoError) {
|
||||
qCWarning(lcRemoteWipe) << QString("Could not parse the JSON returned from the server: <br><em>%1</em>")
|
||||
.arg(jsonParseError.errorString());
|
||||
} else {
|
||||
qCWarning(lcRemoteWipe) << QString("The reply from the server did not contain all expected fields.");
|
||||
}
|
||||
}
|
||||
|
||||
_networkReplySuccess->deleteLater();
|
||||
}
|
||||
}
|
||||
61
src/gui/remotewipe.h
Normal file
61
src/gui/remotewipe.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef REMOTEWIPE_H
|
||||
#define REMOTEWIPE_H
|
||||
|
||||
#include "accountmanager.h"
|
||||
#include <QNetworkAccessManager>
|
||||
|
||||
class QJsonDocument;
|
||||
class TestRemoteWipe;
|
||||
|
||||
namespace OCC {
|
||||
|
||||
class RemoteWipe : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit RemoteWipe(AccountPtr account, QObject *parent = nullptr);
|
||||
|
||||
signals:
|
||||
/**
|
||||
* Notify if wipe was requested
|
||||
*/
|
||||
void authorized(AccountState*);
|
||||
|
||||
/**
|
||||
* Notify if user only needs to login again
|
||||
*/
|
||||
void askUserCredentials();
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* Once receives a 401 or 403 status response it will do a fetch to
|
||||
* <server>/index.php/core/wipe/check
|
||||
*/
|
||||
void startCheckJobWithAppPassword(QString);
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* If wipe is requested, delete account and data, if not continue by asking
|
||||
* the user to login again
|
||||
*/
|
||||
void checkJobSlot();
|
||||
|
||||
/**
|
||||
* Once the client has wiped all the required data a POST to
|
||||
* <server>/index.php/core/wipe/success
|
||||
*/
|
||||
void notifyServerSuccessJob(AccountState *accountState, bool);
|
||||
void notifyServerSuccessJobSlot();
|
||||
|
||||
private:
|
||||
AccountPtr _account;
|
||||
QString _appPassword;
|
||||
bool _accountRemoved;
|
||||
QNetworkAccessManager _networkManager;
|
||||
QNetworkReply *_networkReplyCheck;
|
||||
QNetworkReply *_networkReplySuccess;
|
||||
|
||||
friend class ::TestRemoteWipe;
|
||||
};
|
||||
}
|
||||
#endif // REMOTEWIPE_H
|
||||
@@ -70,7 +70,7 @@ SelectiveSyncWidget::SelectiveSyncWidget(AccountPtr account, QWidget *parent)
|
||||
, _inserting(false)
|
||||
, _folderTree(new QTreeWidget(this))
|
||||
{
|
||||
_loading = new QLabel(tr("Loading ..."), _folderTree);
|
||||
_loading = new QLabel(tr("Loading …"), _folderTree);
|
||||
|
||||
auto layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
@@ -56,10 +56,6 @@ namespace OCC {
|
||||
|
||||
#include "settingsdialogcommon.cpp"
|
||||
|
||||
//
|
||||
// Whenever you change something here check both settingsdialog.cpp and settingsdialogmac.cpp !
|
||||
//
|
||||
|
||||
SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, _ui(new Ui::SettingsDialog)
|
||||
@@ -108,6 +104,9 @@ SettingsDialog::SettingsDialog(ownCloudGui *gui, QWidget *parent)
|
||||
GeneralSettings *generalSettings = new GeneralSettings;
|
||||
_ui->stack->addWidget(generalSettings);
|
||||
|
||||
// Connect styleChanged events to our widgets, so they can adapt (Dark-/Light-Mode switching)
|
||||
connect(this, &SettingsDialog::styleChanged, generalSettings, &GeneralSettings::slotStyleChanged);
|
||||
|
||||
QAction *networkAction = createColorAwareAction(QLatin1String(":/client/resources/network.png"), tr("Network"));
|
||||
_actionGroup->addAction(networkAction);
|
||||
_toolBar->addAction(networkAction);
|
||||
@@ -160,6 +159,9 @@ void SettingsDialog::changeEvent(QEvent *e)
|
||||
case QEvent::PaletteChange:
|
||||
case QEvent::ThemeChange:
|
||||
customizeStyle();
|
||||
|
||||
// Notify the other widgets (Dark-/Light-Mode switching)
|
||||
emit styleChanged();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -252,6 +254,9 @@ void SettingsDialog::accountAdded(AccountState *s)
|
||||
_actionGroupWidgets.insert(accountAction, accountSettings);
|
||||
_actionForAccount.insert(s->account().data(), accountAction);
|
||||
accountAction->trigger();
|
||||
|
||||
// Connect styleChanged event, to adapt (Dark-/Light-Mode switching)
|
||||
connect(this, &SettingsDialog::styleChanged, accountSettings, &AccountSettings::slotStyleChanged);
|
||||
|
||||
connect(accountSettings, &AccountSettings::folderChanged, _gui, &ownCloudGui::slotFoldersChanged);
|
||||
connect(accountSettings, &AccountSettings::openFolderAlias,
|
||||
@@ -344,13 +349,13 @@ void SettingsDialog::accountRemoved(AccountState *s)
|
||||
void SettingsDialog::customizeStyle()
|
||||
{
|
||||
QString highlightColor(palette().highlight().color().name());
|
||||
QString altBase(palette().alternateBase().color().name());
|
||||
QString highlightTextColor(palette().highlightedText().color().name());
|
||||
QString dark(palette().dark().color().name());
|
||||
QString background(palette().base().color().name());
|
||||
_toolBar->setStyleSheet(QString::fromLatin1(TOOLBAR_CSS).arg(background, dark, highlightColor, altBase));
|
||||
_toolBar->setStyleSheet(QString::fromLatin1(TOOLBAR_CSS).arg(background, dark, highlightColor, highlightTextColor));
|
||||
|
||||
Q_FOREACH (QAction *a, _actionGroup->actions()) {
|
||||
QIcon icon = createColorAwareIcon(a->property("iconPath").toString());
|
||||
QIcon icon = Theme::createColorAwareIcon(a->property("iconPath").toString(), palette());
|
||||
a->setIcon(icon);
|
||||
QToolButton *btn = qobject_cast<QToolButton *>(_toolBar->widgetForAction(a));
|
||||
if (btn)
|
||||
@@ -358,34 +363,6 @@ void SettingsDialog::customizeStyle()
|
||||
}
|
||||
}
|
||||
|
||||
static bool isDarkColor(const QColor &color)
|
||||
{
|
||||
// account for different sensitivity of the human eye to certain colors
|
||||
double treshold = 1.0 - (0.299 * color.red() + 0.587 * color.green() + 0.114 * color.blue()) / 255.0;
|
||||
return treshold > 0.5;
|
||||
}
|
||||
|
||||
QIcon SettingsDialog::createColorAwareIcon(const QString &name)
|
||||
{
|
||||
QPalette pal = palette();
|
||||
QImage img(name);
|
||||
QImage inverted(img);
|
||||
inverted.invertPixels(QImage::InvertRgb);
|
||||
|
||||
QIcon icon;
|
||||
if (isDarkColor(pal.color(QPalette::Base))) {
|
||||
icon.addPixmap(QPixmap::fromImage(inverted));
|
||||
} else {
|
||||
icon.addPixmap(QPixmap::fromImage(img));
|
||||
}
|
||||
if (isDarkColor(pal.color(QPalette::HighlightedText))) {
|
||||
icon.addPixmap(QPixmap::fromImage(img), QIcon::Normal, QIcon::On);
|
||||
} else {
|
||||
icon.addPixmap(QPixmap::fromImage(inverted), QIcon::Normal, QIcon::On);
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
class ToolButtonAction : public QWidgetAction
|
||||
{
|
||||
public:
|
||||
@@ -426,7 +403,7 @@ QAction *SettingsDialog::createActionWithIcon(const QIcon &icon, const QString &
|
||||
QAction *SettingsDialog::createColorAwareAction(const QString &iconPath, const QString &text)
|
||||
{
|
||||
// all buttons must have the same size in order to keep a good layout
|
||||
QIcon coloredIcon = createColorAwareIcon(iconPath);
|
||||
QIcon coloredIcon = Theme::createColorAwareIcon(iconPath, palette());
|
||||
return createActionWithIcon(coloredIcon, text, iconPath);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,9 @@ public slots:
|
||||
void slotAccountAvatarChanged();
|
||||
void slotAccountDisplayNameChanged();
|
||||
|
||||
signals:
|
||||
void styleChanged();
|
||||
|
||||
protected:
|
||||
void reject() override;
|
||||
void accept() override;
|
||||
@@ -76,7 +79,6 @@ private:
|
||||
void customizeStyle();
|
||||
void activityAdded(AccountState *);
|
||||
|
||||
QIcon createColorAwareIcon(const QString &name);
|
||||
QAction *createColorAwareAction(const QString &iconName, const QString &fileName);
|
||||
QAction *createActionWithIcon(const QIcon &icon, const QString &text, const QString &iconPath = QString());
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ namespace SettingsDialogCommon
|
||||
{
|
||||
|
||||
/** display name with two lines that is displayed in the settings
|
||||
* If width is bigger than 0, the string will be ellided so it does not exceed that width
|
||||
* If width is bigger than 0, the string will be elided so it does not exceed that width
|
||||
*/
|
||||
QString shortDisplayNameForSettings(Account* account, int width)
|
||||
{
|
||||
|
||||
@@ -1,239 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) by Denis Dzyubenko
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "settingsdialogmac.h"
|
||||
|
||||
#include "macstandardicon.h"
|
||||
|
||||
#include "folderman.h"
|
||||
#include "theme.h"
|
||||
#include "generalsettings.h"
|
||||
#include "networksettings.h"
|
||||
#include "accountsettings.h"
|
||||
#include "accountstate.h"
|
||||
#include "creds/abstractcredentials.h"
|
||||
#include "configfile.h"
|
||||
#include "progressdispatcher.h"
|
||||
#include "owncloudgui.h"
|
||||
#include "activitywidget.h"
|
||||
#include "accountmanager.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QStandardItemModel>
|
||||
#include <QPushButton>
|
||||
#include <QSettings>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
|
||||
namespace OCC {
|
||||
|
||||
#include "settingsdialogcommon.cpp"
|
||||
|
||||
|
||||
// Duplicate in settingsdialog.cpp
|
||||
static QIcon circleMask(const QImage &avatar)
|
||||
{
|
||||
int dim = avatar.width();
|
||||
|
||||
QPixmap fixedImage(dim, dim);
|
||||
fixedImage.fill(Qt::transparent);
|
||||
|
||||
QPainter imgPainter(&fixedImage);
|
||||
QPainterPath clip;
|
||||
clip.addEllipse(0, 0, dim, dim);
|
||||
imgPainter.setClipPath(clip);
|
||||
imgPainter.drawImage(0, 0, avatar);
|
||||
imgPainter.end();
|
||||
|
||||
return QIcon(fixedImage);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Whenever you change something here check both settingsdialog.cpp and settingsdialogmac.cpp !
|
||||
//
|
||||
SettingsDialogMac::SettingsDialogMac(ownCloudGui *gui, QWidget *parent)
|
||||
: MacPreferencesWindow(parent)
|
||||
, _gui(gui)
|
||||
{
|
||||
// do not show minimize button. There is no use, and restoring the
|
||||
// dialog from minimize is broken in MacPreferencesWindow
|
||||
setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint | Qt::WindowMaximizeButtonHint);
|
||||
|
||||
// Emulate dialog behavior: Escape means close
|
||||
QAction *closeDialogAction = new QAction(this);
|
||||
closeDialogAction->setShortcut(QKeySequence(Qt::Key_Escape));
|
||||
connect(closeDialogAction, &QAction::triggered, this, &SettingsDialogMac::close);
|
||||
addAction(closeDialogAction);
|
||||
// People perceive this as a Window, so also make Ctrl+W work
|
||||
QAction *closeWindowAction = new QAction(this);
|
||||
closeWindowAction->setShortcut(QKeySequence("Ctrl+W"));
|
||||
connect(closeWindowAction, &QAction::triggered, this, &SettingsDialogMac::close);
|
||||
addAction(closeWindowAction);
|
||||
// People perceive this as a Window, so also make Ctrl+H work
|
||||
QAction *hideWindowAction = new QAction(this);
|
||||
hideWindowAction->setShortcut(QKeySequence("Ctrl+H"));
|
||||
connect(hideWindowAction, &QAction::triggered, this, &SettingsDialogMac::hide);
|
||||
addAction(hideWindowAction);
|
||||
|
||||
setObjectName("SettingsMac"); // required as group for saveGeometry call
|
||||
|
||||
setWindowTitle(tr("%1").arg(Theme::instance()->appNameGUI()));
|
||||
|
||||
connect(AccountManager::instance(), &AccountManager::accountAdded,
|
||||
this, &SettingsDialogMac::accountAdded);
|
||||
connect(AccountManager::instance(), &AccountManager::accountRemoved,
|
||||
this, &SettingsDialogMac::accountRemoved);
|
||||
|
||||
_actionsIdx = -1;
|
||||
foreach (auto ai, AccountManager::instance()->accounts()) {
|
||||
accountAdded(ai.data());
|
||||
}
|
||||
|
||||
QIcon generalIcon = MacStandardIcon::icon(MacStandardIcon::PreferencesGeneral);
|
||||
GeneralSettings *generalSettings = new GeneralSettings;
|
||||
addPreferencesPanel(generalIcon, tr("General"), generalSettings);
|
||||
|
||||
QIcon networkIcon = MacStandardIcon::icon(MacStandardIcon::Network);
|
||||
NetworkSettings *networkSettings = new NetworkSettings;
|
||||
addPreferencesPanel(networkIcon, tr("Network"), networkSettings);
|
||||
|
||||
QAction *showLogWindow = new QAction(this);
|
||||
showLogWindow->setShortcut(QKeySequence("F12"));
|
||||
connect(showLogWindow, &QAction::triggered, gui, &ownCloudGui::slotToggleLogBrowser);
|
||||
addAction(showLogWindow);
|
||||
|
||||
ConfigFile cfg;
|
||||
cfg.restoreGeometry(this);
|
||||
}
|
||||
|
||||
void SettingsDialogMac::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
ConfigFile cfg;
|
||||
cfg.saveGeometry(this);
|
||||
MacPreferencesWindow::closeEvent(event);
|
||||
}
|
||||
|
||||
void SettingsDialogMac::showActivityPage()
|
||||
{
|
||||
// Count backwards (0-based) from the last panel (multiple accounts can be on the left)
|
||||
setCurrentPanelIndex(preferencePanelCount() - 1 - 2);
|
||||
}
|
||||
|
||||
void SettingsDialogMac::accountAdded(AccountState *s)
|
||||
{
|
||||
QIcon accountIcon = MacStandardIcon::icon(MacStandardIcon::UserAccounts);
|
||||
auto accountSettings = new AccountSettings(s, this);
|
||||
QString displayName = Theme::instance()->multiAccount() ? SettingsDialogCommon::shortDisplayNameForSettings(s->account().data(), 0) : tr("Account");
|
||||
|
||||
// this adds the panel - nothing to add here just to fix the order
|
||||
insertPreferencesPanel(++_actionsIdx, accountIcon, displayName, accountSettings);
|
||||
|
||||
connect(accountSettings, &AccountSettings::folderChanged, _gui, &ownCloudGui::slotFoldersChanged);
|
||||
connect(accountSettings, &AccountSettings::openFolderAlias, _gui, &ownCloudGui::slotFolderOpenAction);
|
||||
|
||||
connect(s->account().data(), &Account::accountChangedAvatar, this, &SettingsDialogMac::slotAccountAvatarChanged);
|
||||
connect(s->account().data(), &Account::accountChangedDisplayName, this, &SettingsDialogMac::slotAccountDisplayNameChanged);
|
||||
|
||||
// Refresh immediatly when getting online
|
||||
connect(s, &AccountState::isConnectedChanged, this, &SettingsDialogMac::slotRefreshActivityAccountStateSender);
|
||||
|
||||
// Add activity panel
|
||||
QIcon activityIcon(QLatin1String(":/client/resources/activity.png"));
|
||||
_activitySettings[s] = new ActivitySettings(s, this);
|
||||
insertPreferencesPanel(++_actionsIdx, activityIcon, tr("Activity"), _activitySettings[s]);
|
||||
connect(_activitySettings[s], SIGNAL(guiLog(QString, QString)), _gui,
|
||||
SLOT(slotShowOptionalTrayMessage(QString, QString)));
|
||||
|
||||
// if this is not the first account, add separator 2 positions before int the toolbar
|
||||
if(AccountManager::instance()->accounts().first().data() != s &&
|
||||
AccountManager::instance()->accounts().size() >= 1){
|
||||
_separators[s] = insertSeparator(_actionsIdx - 1);
|
||||
++_actionsIdx; //we have one more item in the toolbar
|
||||
}
|
||||
|
||||
ConfigFile cfg;
|
||||
_activitySettings[s]->setNotificationRefreshInterval(cfg.notificationRefreshInterval());
|
||||
|
||||
slotRefreshActivity(s);
|
||||
setCurrentPanelIndex(0);
|
||||
}
|
||||
|
||||
void SettingsDialogMac::accountRemoved(AccountState *s)
|
||||
{
|
||||
auto list = findChildren<AccountSettings *>(QString());
|
||||
foreach (auto p, list) {
|
||||
if (p->accountsState() == s) {
|
||||
removePreferencesPanel(p);
|
||||
|
||||
// remove settings panel
|
||||
if(_activitySettings.contains(s))
|
||||
removePreferencesPanel(_activitySettings[s]);
|
||||
|
||||
// remove separator if there is any
|
||||
if(_separators.contains(s)){
|
||||
removeSeparator(_separators[s]);
|
||||
_separators.remove(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDialogMac::slotRefreshActivityAccountStateSender()
|
||||
{
|
||||
slotRefreshActivity(qobject_cast<AccountState*>(sender()));
|
||||
}
|
||||
|
||||
void SettingsDialogMac::slotRefreshActivity(AccountState *accountState)
|
||||
{
|
||||
if (accountState) {
|
||||
_activitySettings[accountState]->slotRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDialogMac::slotAccountAvatarChanged()
|
||||
{
|
||||
Account *account = static_cast<Account *>(sender());
|
||||
auto list = findChildren<AccountSettings *>(QString());
|
||||
foreach (auto p, list) {
|
||||
if (p->accountsState()->account() == account) {
|
||||
int idx = indexForPanel(p);
|
||||
QImage pix = account->avatar();
|
||||
if (!pix.isNull()) {
|
||||
setPreferencesPanelIcon(idx, circleMask(pix));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDialogMac::slotAccountDisplayNameChanged()
|
||||
{
|
||||
Account *account = static_cast<Account *>(sender());
|
||||
auto list = findChildren<AccountSettings *>(QString());
|
||||
foreach (auto p, list) {
|
||||
if (p->accountsState()->account() == account) {
|
||||
int idx = indexForPanel(p);
|
||||
QString displayName = account->displayName();
|
||||
if (!displayName.isNull()) {
|
||||
displayName = Theme::instance()->multiAccount()
|
||||
? SettingsDialogCommon::shortDisplayNameForSettings(account, 0)
|
||||
: tr("Account");
|
||||
setPreferencesPanelTitle(idx, displayName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) by Denis Dzyubenko
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SETTINGSDIALOGMAC_H
|
||||
#define SETTINGSDIALOGMAC_H
|
||||
|
||||
#include "progressdispatcher.h"
|
||||
#include "macpreferenceswindow.h"
|
||||
#include "owncloudgui.h"
|
||||
|
||||
class QStandardItemModel;
|
||||
class QListWidgetItem;
|
||||
|
||||
namespace OCC {
|
||||
|
||||
class AccountSettings;
|
||||
class Application;
|
||||
class FolderMan;
|
||||
class ownCloudGui;
|
||||
class Folder;
|
||||
class AccountState;
|
||||
class ActivitySettings;
|
||||
|
||||
/**
|
||||
* @brief The SettingsDialogMac class
|
||||
* @ingroup gui
|
||||
*/
|
||||
class SettingsDialogMac : public MacPreferencesWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SettingsDialogMac(ownCloudGui *gui, QWidget *parent = 0);
|
||||
|
||||
public slots:
|
||||
void showActivityPage();
|
||||
void slotRefreshActivity(AccountState *accountState);
|
||||
void slotRefreshActivityAccountStateSender();
|
||||
|
||||
private slots:
|
||||
void accountAdded(AccountState *);
|
||||
void accountRemoved(AccountState *);
|
||||
void slotAccountAvatarChanged();
|
||||
void slotAccountDisplayNameChanged();
|
||||
|
||||
private:
|
||||
void closeEvent(QCloseEvent *event);
|
||||
|
||||
QAction *_actionBefore;
|
||||
int _actionsIdx;
|
||||
QMap<AccountState *, QAction *> _separators;
|
||||
|
||||
QMap<AccountState *, ActivitySettings *> _activitySettings;
|
||||
ownCloudGui *_gui;
|
||||
|
||||
int _protocolIdx;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // SETTINGSDIALOGMAC_H
|
||||
;
|
||||
@@ -156,6 +156,9 @@ void ShareDialog::addLinkShareWidget(const QSharedPointer<LinkShare> &linkShare)
|
||||
connect(_linkWidgetList.at(index), &ShareLinkWidget::deleteLinkShare, this, &ShareDialog::slotDeleteShare);
|
||||
//connect(_linkWidgetList.at(index), &ShareLinkWidget::resizeRequested, this, &ShareDialog::slotAdjustScrollWidgetSize);
|
||||
|
||||
// Connect styleChanged events to our widget, so it can adapt (Dark-/Light-Mode switching)
|
||||
connect(this, &ShareDialog::styleChanged, _linkWidgetList.at(index), &ShareLinkWidget::slotStyleChanged);
|
||||
|
||||
_ui->verticalLayout->insertWidget(_linkWidgetList.size()+1, _linkWidgetList.at(index));
|
||||
_linkWidgetList.at(index)->setupUiOptions();
|
||||
}
|
||||
@@ -282,6 +285,10 @@ void ShareDialog::showSharingUi()
|
||||
|
||||
if (userGroupSharing) {
|
||||
_userGroupWidget = new ShareUserGroupWidget(_accountState->account(), _sharePath, _localPath, _maxSharingPermissions, _privateLinkUrl, this);
|
||||
|
||||
// Connect styleChanged events to our widget, so it can adapt (Dark-/Light-Mode switching)
|
||||
connect(this, &ShareDialog::styleChanged, _userGroupWidget, &ShareUserGroupWidget::slotStyleChanged);
|
||||
|
||||
_ui->verticalLayout->insertWidget(1, _userGroupWidget);
|
||||
_userGroupWidget->getShares();
|
||||
}
|
||||
@@ -335,4 +342,21 @@ void ShareDialog::slotAccountStateChanged(int state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShareDialog::changeEvent(QEvent *e)
|
||||
{
|
||||
switch (e->type()) {
|
||||
case QEvent::StyleChange:
|
||||
case QEvent::PaletteChange:
|
||||
case QEvent::ThemeChange:
|
||||
// Notify the other widgets (Dark-/Light-Mode switching)
|
||||
emit styleChanged();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
QDialog::changeEvent(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -68,6 +68,10 @@ private slots:
|
||||
|
||||
signals:
|
||||
void toggleAnimation(bool);
|
||||
void styleChanged();
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent *) override;
|
||||
|
||||
private:
|
||||
void showSharingUi();
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "capabilities.h"
|
||||
#include "guiutility.h"
|
||||
#include "sharemanager.h"
|
||||
#include "theme.h"
|
||||
|
||||
#include "QProgressIndicator.h"
|
||||
#include <QBuffer>
|
||||
@@ -240,6 +241,8 @@ void ShareLinkWidget::setupUiOptions(){
|
||||
|
||||
//TO DO
|
||||
//startAnimation(0, height());
|
||||
|
||||
customizeStyle();
|
||||
}
|
||||
|
||||
void ShareLinkWidget::slotCopyLinkShare(bool clicked){
|
||||
@@ -489,4 +492,30 @@ void ShareLinkWidget::displayError(const QString &errMsg)
|
||||
_ui->errorLabel->setText(errMsg);
|
||||
_ui->errorLabel->show();
|
||||
}
|
||||
|
||||
void ShareLinkWidget::slotStyleChanged()
|
||||
{
|
||||
customizeStyle();
|
||||
}
|
||||
|
||||
void ShareLinkWidget::customizeStyle()
|
||||
{
|
||||
_unshareLinkAction->setIcon(Theme::createColorAwareIcon(":/client/resources/delete.png"));
|
||||
|
||||
_addAnotherLinkAction->setIcon(Theme::createColorAwareIcon(":/client/resources/add.png"));
|
||||
|
||||
_ui->enableShareLink->setIcon(Theme::createColorAwareIcon(":/client/resources/copy.svg"));
|
||||
|
||||
// only on master, not in stable-2.6 yet
|
||||
// _ui->shareLinkIconLabel->setPixmap(Theme::createColorAwarePixmap(":/client/resources/public.svg"));
|
||||
_ui->createShareButton->setIcon(Theme::createColorAwareIcon(":/client/resources/public.svg"));
|
||||
|
||||
_ui->shareLinkToolButton->setIcon(Theme::createColorAwareIcon(":/client/resources/more.svg"));
|
||||
|
||||
// only on master, not in stable-2.6 yet
|
||||
// _ui->confirmNote->setIcon(Theme::createColorAwareIcon(":/client/resources/confirm.svg"));
|
||||
_ui->confirmPassword->setIcon(Theme::createColorAwareIcon(":/client/resources/confirm.svg"));
|
||||
_ui->confirmExpirationDate->setIcon(Theme::createColorAwareIcon(":/client/resources/confirm.svg"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ public slots:
|
||||
void slotToggleAnimation(bool start);
|
||||
void slotServerError(int code, const QString &message);
|
||||
void slotCreateShareRequiresPassword(const QString &message);
|
||||
void slotStyleChanged();
|
||||
|
||||
private slots:
|
||||
void slotCreateShareLink(bool clicked);
|
||||
@@ -107,6 +108,8 @@ private:
|
||||
|
||||
void startAnimation(const int start, const int end);
|
||||
|
||||
void customizeStyle();
|
||||
|
||||
Ui::ShareLinkWidget *_ui;
|
||||
AccountPtr _account;
|
||||
QString _sharePath;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "thumbnailjob.h"
|
||||
#include "sharee.h"
|
||||
#include "sharemanager.h"
|
||||
#include "theme.h"
|
||||
|
||||
#include "QProgressIndicator.h"
|
||||
#include <QBuffer>
|
||||
@@ -112,6 +113,8 @@ ShareUserGroupWidget::ShareUserGroupWidget(AccountPtr account,
|
||||
//_ui->shareeHorizontalLayout->addWidget(&_pi_sharee);
|
||||
|
||||
_parentScrollArea = parentWidget()->findChild<QScrollArea*>("scrollArea");
|
||||
|
||||
customizeStyle();
|
||||
}
|
||||
|
||||
ShareUserGroupWidget::~ShareUserGroupWidget()
|
||||
@@ -211,6 +214,10 @@ void ShareUserGroupWidget::slotSharesFetched(const QList<QSharedPointer<Share>>
|
||||
connect(s, &ShareUserLine::resizeRequested, this, &ShareUserGroupWidget::slotAdjustScrollWidgetSize);
|
||||
connect(s, &ShareUserLine::visualDeletionDone, this, &ShareUserGroupWidget::getShares);
|
||||
s->setBackgroundRole(layout->count() % 2 == 0 ? QPalette::Base : QPalette::AlternateBase);
|
||||
|
||||
// Connect styleChanged events to our widget, so it can adapt (Dark-/Light-Mode switching)
|
||||
connect(this, &ShareUserGroupWidget::styleChanged, s, &ShareUserLine::slotStyleChanged);
|
||||
|
||||
layout->addWidget(s);
|
||||
|
||||
x++;
|
||||
@@ -255,7 +262,8 @@ void ShareUserGroupWidget::slotPrivateLinkShare()
|
||||
auto menu = new QMenu(this);
|
||||
menu->setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
menu->addAction(QIcon(":/client/resources/copy.svg"),
|
||||
// this icon is not handled by slotStyleChanged() -> customizeStyle but we can live with that
|
||||
menu->addAction(Theme::createColorAwareIcon(":/client/resources/copy.svg"),
|
||||
tr("Copy link"),
|
||||
this, SLOT(slotPrivateLinkCopy()));
|
||||
|
||||
@@ -358,6 +366,19 @@ void ShareUserGroupWidget::slotPrivateLinkEmail()
|
||||
this);
|
||||
}
|
||||
|
||||
void ShareUserGroupWidget::slotStyleChanged()
|
||||
{
|
||||
customizeStyle();
|
||||
|
||||
// Notify the other widgets (ShareUserLine in this case, Dark-/Light-Mode switching)
|
||||
emit styleChanged();
|
||||
}
|
||||
|
||||
void ShareUserGroupWidget::customizeStyle()
|
||||
{
|
||||
_ui->confirmShare->setIcon(Theme::createColorAwareIcon(":/client/resources/confirm.svg"));
|
||||
}
|
||||
|
||||
ShareUserLine::ShareUserLine(QSharedPointer<Share> share,
|
||||
SharePermissions maxSharingPermissions,
|
||||
bool isFile,
|
||||
@@ -423,8 +444,9 @@ ShareUserLine::ShareUserLine(QSharedPointer<Share> share,
|
||||
_ui->permissionToolButton->setMenu(menu);
|
||||
_ui->permissionToolButton->setPopupMode(QToolButton::InstantPopup);
|
||||
|
||||
QIcon icon(QLatin1String(":/client/resources/more.svg"));
|
||||
_ui->permissionToolButton->setIcon(icon);
|
||||
// icon now set in: customizeStyle
|
||||
/*QIcon icon(QLatin1String(":/client/resources/more.svg"));
|
||||
_ui->permissionToolButton->setIcon(icon);*/
|
||||
|
||||
// Set the permissions checkboxes
|
||||
displayPermissions();
|
||||
@@ -451,6 +473,8 @@ ShareUserLine::ShareUserLine(QSharedPointer<Share> share,
|
||||
}
|
||||
|
||||
loadAvatar();
|
||||
|
||||
customizeStyle();
|
||||
}
|
||||
|
||||
void ShareUserLine::loadAvatar()
|
||||
@@ -645,4 +669,18 @@ void ShareUserLine::displayPermissions()
|
||||
_permissionDelete->setChecked(perm & SharePermissionDelete);
|
||||
}
|
||||
}
|
||||
|
||||
void ShareUserLine::slotStyleChanged()
|
||||
{
|
||||
customizeStyle();
|
||||
}
|
||||
|
||||
void ShareUserLine::customizeStyle()
|
||||
{
|
||||
_ui->permissionToolButton->setIcon(Theme::createColorAwareIcon(":/client/resources/more.svg"));
|
||||
|
||||
QIcon deleteicon = QIcon::fromTheme(QLatin1String("user-trash"),Theme::createColorAwareIcon(QLatin1String(":/client/resources/delete.png")));
|
||||
_deleteShareButton->setIcon(deleteicon);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -64,9 +64,11 @@ public:
|
||||
|
||||
signals:
|
||||
void togglePublicLinkShare(bool);
|
||||
void styleChanged();
|
||||
|
||||
public slots:
|
||||
void getShares();
|
||||
void slotStyleChanged();
|
||||
|
||||
private slots:
|
||||
void slotSharesFetched(const QList<QSharedPointer<Share>> &shares);
|
||||
@@ -88,6 +90,8 @@ private slots:
|
||||
void slotPrivateLinkEmail();
|
||||
|
||||
private:
|
||||
void customizeStyle();
|
||||
|
||||
Ui::ShareUserGroupWidget *_ui;
|
||||
QScrollArea *_parentScrollArea;
|
||||
AccountPtr _account;
|
||||
@@ -127,6 +131,9 @@ signals:
|
||||
void visualDeletionDone();
|
||||
void resizeRequested();
|
||||
|
||||
public slots:
|
||||
void slotStyleChanged();
|
||||
|
||||
private slots:
|
||||
void on_deleteShareButton_clicked();
|
||||
void slotPermissionsChanged();
|
||||
@@ -141,6 +148,7 @@ private slots:
|
||||
private:
|
||||
void displayPermissions();
|
||||
void loadAvatar();
|
||||
void customizeStyle();
|
||||
|
||||
Ui::ShareUserLine *_ui;
|
||||
QSharedPointer<Share> _share;
|
||||
|
||||
@@ -623,9 +623,9 @@ void SocketApi::command_GET_STRINGS(const QString &argument, SocketListener *lis
|
||||
{
|
||||
static std::array<std::pair<const char *, QString>, 5> strings { {
|
||||
{ "SHARE_MENU_TITLE", tr("Share options") },
|
||||
{ "CONTEXT_MENU_TITLE", tr("Share via ") + Theme::instance()->appNameGUI()},
|
||||
{ "CONTEXT_MENU_TITLE", tr("Share via %1").arg(Theme::instance()->appNameGUI())},
|
||||
{ "COPY_PRIVATE_LINK_MENU_TITLE", tr("Copy private link to clipboard") },
|
||||
{ "EMAIL_PRIVATE_LINK_MENU_TITLE", tr("Send private link by email...") },
|
||||
{ "EMAIL_PRIVATE_LINK_MENU_TITLE", tr("Send private link by email …") },
|
||||
} };
|
||||
listener->sendMessage(QString("GET_STRINGS:BEGIN"));
|
||||
for (const auto& key_value : strings) {
|
||||
@@ -673,7 +673,7 @@ void SocketApi::sendSharingContextMenuOptions(const FileData &fileData, SocketLi
|
||||
|
||||
// Disabled: only providing email option for private links would look odd,
|
||||
// and the copy option is more general.
|
||||
//listener->sendMessage(QLatin1String("MENU_ITEM:EMAIL_PRIVATE_LINK") + flagString + tr("Send private link by email..."));
|
||||
//listener->sendMessage(QLatin1String("MENU_ITEM:EMAIL_PRIVATE_LINK") + flagString + tr("Send private link by email …"));
|
||||
}
|
||||
|
||||
SocketApi::FileData SocketApi::FileData::get(const QString &localFile)
|
||||
|
||||
@@ -142,7 +142,7 @@ QMenu *SslButton::buildCertMenu(QMenu *parent, const QSslCertificate &cert,
|
||||
|
||||
// create label first
|
||||
QLabel *label = new QLabel(parent);
|
||||
label->setStyleSheet(QLatin1String("QLabel { padding: 8px; background-color: #fff; }"));
|
||||
label->setStyleSheet(QLatin1String("QLabel { padding: 8px; }"));
|
||||
label->setTextFormat(Qt::RichText);
|
||||
label->setText(details);
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ QString OCUpdater::statusString() const
|
||||
|
||||
switch (downloadState()) {
|
||||
case Downloading:
|
||||
return tr("Downloading version %1. Please wait...").arg(updateVersion);
|
||||
return tr("Downloading version %1. Please wait …").arg(updateVersion);
|
||||
case DownloadComplete:
|
||||
return tr("%1 version %2 available. Restart application to start the update.").arg(Theme::instance()->appNameGUI(), updateVersion);
|
||||
case DownloadFailed:
|
||||
@@ -148,9 +148,9 @@ QString OCUpdater::statusString() const
|
||||
case DownloadTimedOut:
|
||||
return tr("Could not check for new updates.");
|
||||
case UpdateOnlyAvailableThroughSystem:
|
||||
return tr("New %1 version %2 available. Please use the system's update tool to install it.").arg(Theme::instance()->appNameGUI(), updateVersion);
|
||||
return tr("New %1 version %2 is available. Please click <a href='%3'>here</a> to download the update.").arg(Theme::instance()->appNameGUI(), updateVersion, _updateInfo.web());
|
||||
case CheckingServer:
|
||||
return tr("Checking update server...");
|
||||
return tr("Checking update server …");
|
||||
case Unknown:
|
||||
return tr("Update status is unknown: Did not check for new updates.");
|
||||
case UpToDate:
|
||||
|
||||
@@ -99,6 +99,7 @@ void Flow2AuthCredsPage::asyncAuthResult(Flow2Auth::Result r, const QString &use
|
||||
_appPassword = appPassword;
|
||||
OwncloudWizard *ocWizard = qobject_cast<OwncloudWizard *>(wizard());
|
||||
Q_ASSERT(ocWizard);
|
||||
|
||||
emit connectToOCUrl(ocWizard->account()->url().toString());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ OwncloudAdvancedSetupPage::OwncloudAdvancedSetupPage()
|
||||
setupCustomization();
|
||||
|
||||
connect(_ui.pbSelectLocalFolder, &QAbstractButton::clicked, this, &OwncloudAdvancedSetupPage::slotSelectFolder);
|
||||
setButtonText(QWizard::NextButton, tr("Connect..."));
|
||||
setButtonText(QWizard::NextButton, tr("Connect …"));
|
||||
|
||||
connect(_ui.rSyncEverything, &QAbstractButton::clicked, this, &OwncloudAdvancedSetupPage::slotSyncEverythingClicked);
|
||||
connect(_ui.rSelectiveSync, &QAbstractButton::clicked, this, &OwncloudAdvancedSetupPage::slotSelectiveSyncClicked);
|
||||
|
||||
@@ -160,6 +160,39 @@ void AbstractNetworkJob::slotFinished()
|
||||
qCWarning(lcNetworkJob) << "SslHandshakeFailedError: " << errorString() << " : can be caused by a webserver wanting SSL client certificates";
|
||||
}
|
||||
|
||||
#if (QT_VERSION >= 0x050800)
|
||||
// Qt doesn't yet transparently resend HTTP2 requests, do so here
|
||||
const auto maxHttp2Resends = 5;
|
||||
QByteArray verb = requestVerb(*reply());
|
||||
if (_reply->error() == QNetworkReply::ContentReSendError
|
||||
&& _reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute).toBool()) {
|
||||
|
||||
if ((_requestBody && !_requestBody->isSequential()) || verb.isEmpty()) {
|
||||
qCWarning(lcNetworkJob) << "Can't resend HTTP2 request, verb or body not suitable"
|
||||
<< _reply->request().url() << verb << _requestBody;
|
||||
} else if (_http2ResendCount >= maxHttp2Resends) {
|
||||
qCWarning(lcNetworkJob) << "Not resending HTTP2 request, number of resends exhausted"
|
||||
<< _reply->request().url() << _http2ResendCount;
|
||||
} else {
|
||||
qCInfo(lcNetworkJob) << "HTTP2 resending" << _reply->request().url();
|
||||
_http2ResendCount++;
|
||||
|
||||
resetTimeout();
|
||||
if (_requestBody) {
|
||||
if(!_requestBody->isOpen())
|
||||
_requestBody->open(QIODevice::ReadOnly);
|
||||
_requestBody->seek(0);
|
||||
}
|
||||
sendRequest(
|
||||
verb,
|
||||
_reply->request().url(),
|
||||
_reply->request(),
|
||||
_requestBody);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (_reply->error() != QNetworkReply::NoError) {
|
||||
if (!_ignoreCredentialFailure || _reply->error() != QNetworkReply::AuthenticationRequiredError) {
|
||||
qCWarning(lcNetworkJob) << _reply->error() << errorString()
|
||||
|
||||
@@ -188,7 +188,10 @@ private:
|
||||
QPointer<QNetworkReply> _reply; // (QPointer because the NetworkManager may be destroyed before the jobs at exit)
|
||||
QString _path;
|
||||
QTimer _timer;
|
||||
int _redirectCount;
|
||||
int _redirectCount = 0;
|
||||
#if (QT_VERSION >= 0x050800)
|
||||
int _http2ResendCount = 0;
|
||||
#endif
|
||||
|
||||
// Set by the xyzRequest() functions and needed to be able to redirect
|
||||
// requests, should it be required.
|
||||
|
||||
@@ -36,9 +36,15 @@
|
||||
#include <QAuthenticator>
|
||||
#include <QStandardPaths>
|
||||
|
||||
#include <keychain.h>
|
||||
#include "creds/abstractcredentials.h"
|
||||
|
||||
using namespace QKeychain;
|
||||
|
||||
namespace OCC {
|
||||
|
||||
Q_LOGGING_CATEGORY(lcAccount, "nextcloud.sync.account", QtInfoMsg)
|
||||
const char app_password[] = "_app-password";
|
||||
|
||||
Account::Account(QObject *parent)
|
||||
: QObject(parent)
|
||||
@@ -53,16 +59,17 @@ AccountPtr Account::create()
|
||||
AccountPtr acc = AccountPtr(new Account);
|
||||
acc->setSharedThis(acc);
|
||||
|
||||
//TODO: This probably needs to have a better
|
||||
// coupling, but it should work for now.
|
||||
acc->e2e()->setAccount(acc);
|
||||
//TODO: This probably needs to have a better
|
||||
// coupling, but it should work for now.
|
||||
acc->e2e()->setAccount(acc);
|
||||
|
||||
return acc;
|
||||
}
|
||||
|
||||
ClientSideEncryption* Account::e2e()
|
||||
{
|
||||
// Qt expects everything in the connect to be a pointer, so return a pointer.
|
||||
return &_e2e;
|
||||
// Qt expects everything in the connect to be a pointer, so return a pointer.
|
||||
return &_e2e;
|
||||
}
|
||||
|
||||
Account::~Account()
|
||||
@@ -119,7 +126,7 @@ void Account::setAvatar(const QImage &img)
|
||||
|
||||
QString Account::displayName() const
|
||||
{
|
||||
QString dn = QString("%1@%2").arg(davUser(), _url.host());
|
||||
QString dn = QString("%1@%2").arg(credentials()->user(), _url.host());
|
||||
int port = url().port();
|
||||
if (port > 0 && port != 80 && port != 443) {
|
||||
dn.append(QLatin1Char(':'));
|
||||
@@ -432,6 +439,9 @@ void Account::slotCredentialsAsked()
|
||||
|
||||
void Account::handleInvalidCredentials()
|
||||
{
|
||||
// Retrieving password will trigger remote wipe check job
|
||||
retrieveAppPassword();
|
||||
|
||||
emit invalidCredentials();
|
||||
}
|
||||
|
||||
@@ -503,4 +513,91 @@ void Account::setNonShib(bool nonShib)
|
||||
}
|
||||
}
|
||||
|
||||
void Account::writeAppPasswordOnce(QString appPassword){
|
||||
if(_wroteAppPassword)
|
||||
return;
|
||||
|
||||
// Fix: Password got written from Account Wizard, before finish.
|
||||
// Only write the app password for a connected account, else
|
||||
// there'll be a zombie keychain slot forever, never used again ;p
|
||||
//
|
||||
// Also don't write empty passwords (Log out -> Relaunch)
|
||||
if(id().isEmpty() || appPassword.isEmpty())
|
||||
return;
|
||||
|
||||
const QString kck = AbstractCredentials::keychainKey(
|
||||
url().toString(),
|
||||
davUser() + app_password,
|
||||
id()
|
||||
);
|
||||
|
||||
WritePasswordJob *job = new WritePasswordJob(Theme::instance()->appName());
|
||||
job->setInsecureFallback(false);
|
||||
job->setKey(kck);
|
||||
job->setBinaryData(appPassword.toLatin1());
|
||||
connect(job, &WritePasswordJob::finished, [this](Job *incoming) {
|
||||
WritePasswordJob *writeJob = static_cast<WritePasswordJob *>(incoming);
|
||||
if (writeJob->error() == NoError)
|
||||
qCInfo(lcAccount) << "appPassword stored in keychain";
|
||||
else
|
||||
qCWarning(lcAccount) << "Unable to store appPassword in keychain" << writeJob->errorString();
|
||||
|
||||
// We don't try this again on error, to not raise CPU consumption
|
||||
_wroteAppPassword = true;
|
||||
});
|
||||
job->start();
|
||||
}
|
||||
|
||||
void Account::retrieveAppPassword(){
|
||||
const QString kck = AbstractCredentials::keychainKey(
|
||||
url().toString(),
|
||||
credentials()->user() + app_password,
|
||||
id()
|
||||
);
|
||||
|
||||
ReadPasswordJob *job = new ReadPasswordJob(Theme::instance()->appName());
|
||||
job->setInsecureFallback(false);
|
||||
job->setKey(kck);
|
||||
connect(job, &ReadPasswordJob::finished, [this](Job *incoming) {
|
||||
ReadPasswordJob *readJob = static_cast<ReadPasswordJob *>(incoming);
|
||||
QString pwd("");
|
||||
// Error or no valid public key error out
|
||||
if (readJob->error() == NoError &&
|
||||
readJob->binaryData().length() > 0) {
|
||||
pwd = readJob->binaryData();
|
||||
}
|
||||
|
||||
emit appPasswordRetrieved(pwd);
|
||||
});
|
||||
job->start();
|
||||
}
|
||||
|
||||
void Account::deleteAppPassword(){
|
||||
const QString kck = AbstractCredentials::keychainKey(
|
||||
url().toString(),
|
||||
credentials()->user() + app_password,
|
||||
id()
|
||||
);
|
||||
|
||||
if (kck.isEmpty()) {
|
||||
qCDebug(lcAccount) << "appPassword is empty";
|
||||
return;
|
||||
}
|
||||
|
||||
DeletePasswordJob *job = new DeletePasswordJob(Theme::instance()->appName());
|
||||
job->setInsecureFallback(false);
|
||||
job->setKey(kck);
|
||||
connect(job, &DeletePasswordJob::finished, [this](Job *incoming) {
|
||||
DeletePasswordJob *deleteJob = static_cast<DeletePasswordJob *>(incoming);
|
||||
if (deleteJob->error() == NoError)
|
||||
qCInfo(lcAccount) << "appPassword deleted from keychain";
|
||||
else
|
||||
qCWarning(lcAccount) << "Unable to delete appPassword from keychain" << deleteJob->errorString();
|
||||
|
||||
// Allow storing a new app password on re-login
|
||||
_wroteAppPassword = false;
|
||||
});
|
||||
job->start();
|
||||
}
|
||||
|
||||
} // namespace OCC
|
||||
|
||||
@@ -41,6 +41,12 @@ class QNetworkReply;
|
||||
class QUrl;
|
||||
class QNetworkAccessManager;
|
||||
|
||||
namespace QKeychain {
|
||||
class Job;
|
||||
class WritePasswordJob;
|
||||
class ReadPasswordJob;
|
||||
}
|
||||
|
||||
namespace OCC {
|
||||
|
||||
class AbstractCredentials;
|
||||
@@ -50,7 +56,6 @@ class QuotaInfo;
|
||||
class AccessManager;
|
||||
class SimpleNetworkJob;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Reimplement this to handle SSL errors from libsync
|
||||
* @ingroup libsync
|
||||
@@ -236,6 +241,11 @@ public:
|
||||
|
||||
ClientSideEncryption* e2e();
|
||||
|
||||
/// Used in RemoteWipe
|
||||
void retrieveAppPassword();
|
||||
void writeAppPasswordOnce(QString appPassword);
|
||||
void deleteAppPassword();
|
||||
|
||||
public slots:
|
||||
/// Used when forgetting credentials
|
||||
void clearQNAMCache();
|
||||
@@ -262,6 +272,9 @@ signals:
|
||||
void accountChangedAvatar();
|
||||
void accountChangedDisplayName();
|
||||
|
||||
/// Used in RemoteWipe
|
||||
void appPasswordRetrieved(QString);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void slotCredentialsFetched();
|
||||
void slotCredentialsAsked();
|
||||
@@ -306,7 +319,26 @@ private:
|
||||
QString _davPath; // defaults to value from theme, might be overwritten in brandings
|
||||
ClientSideEncryption _e2e;
|
||||
|
||||
/// Used in RemoteWipe
|
||||
bool _wroteAppPassword = false;
|
||||
|
||||
friend class AccountManager;
|
||||
|
||||
/* IMPORTANT - remove later - FIXME MS@2019-12-07 -->
|
||||
* TODO: For "Log out" & "Remove account": Remove client CA certs and KEY!
|
||||
*
|
||||
* Disabled as long as selecting another cert is not supported by the UI.
|
||||
*
|
||||
* Being able to specify a new certificate is important anyway: expiry etc.
|
||||
*
|
||||
* We introduce this dirty hack here, to allow deleting them upon Remote Wipe.
|
||||
*/
|
||||
public:
|
||||
void setRemoteWipeRequested_HACK() { _isRemoteWipeRequested_HACK = true; }
|
||||
bool isRemoteWipeRequested_HACK() { return _isRemoteWipeRequested_HACK; }
|
||||
private:
|
||||
bool _isRemoteWipeRequested_HACK = false;
|
||||
// <-- FIXME MS@2019-12-07
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#include <QOperatingSystemVersion>
|
||||
#endif
|
||||
|
||||
#define DEFAULT_REMOTE_POLL_INTERVAL 5000 // default remote poll time in milliseconds
|
||||
#define DEFAULT_REMOTE_POLL_INTERVAL 30000 // default remote poll time in milliseconds
|
||||
#define DEFAULT_MAX_LOG_LINES 20000
|
||||
|
||||
namespace OCC {
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QLoggingCategory>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkAccessManager>
|
||||
@@ -872,14 +873,23 @@ void DetermineAuthTypeJob::start()
|
||||
// Don't send cookies, we can't determine the auth type if we're logged in
|
||||
req.setAttribute(QNetworkRequest::CookieLoadControlAttribute, QNetworkRequest::Manual);
|
||||
|
||||
// Start two parallel requests, one determines whether it's a shib server
|
||||
// and the other checks the HTTP auth method.
|
||||
// Start three parallel requests
|
||||
|
||||
// 1. determines whether it's a shib server
|
||||
auto get = _account->sendRequest("GET", _account->davUrl(), req);
|
||||
|
||||
// 2. checks the HTTP auth method.
|
||||
auto propfind = _account->sendRequest("PROPFIND", _account->davUrl(), req);
|
||||
|
||||
// 3. Determines if the old flow has to be used (GS for now)
|
||||
auto oldFlowRequired = new JsonApiJob(_account, "/ocs/v2.php/cloud/capabilities", this);
|
||||
|
||||
get->setTimeout(30 * 1000);
|
||||
propfind->setTimeout(30 * 1000);
|
||||
oldFlowRequired->setTimeout(30 * 1000);
|
||||
get->setIgnoreCredentialFailure(true);
|
||||
propfind->setIgnoreCredentialFailure(true);
|
||||
oldFlowRequired->setIgnoreCredentialFailure(true);
|
||||
|
||||
connect(get, &AbstractNetworkJob::redirected, this, [this, get](QNetworkReply *, const QUrl &target, int) {
|
||||
#ifndef NO_SHIBBOLETH
|
||||
@@ -897,7 +907,7 @@ void DetermineAuthTypeJob::start()
|
||||
});
|
||||
connect(get, &SimpleNetworkJob::finishedSignal, this, [this]() {
|
||||
_getDone = true;
|
||||
checkBothDone();
|
||||
checkAllDone();
|
||||
});
|
||||
connect(propfind, &SimpleNetworkJob::finishedSignal, this, [this](QNetworkReply *reply) {
|
||||
auto authChallenge = reply->rawHeader("WWW-Authenticate").toLower();
|
||||
@@ -907,14 +917,37 @@ void DetermineAuthTypeJob::start()
|
||||
qCWarning(lcDetermineAuthTypeJob) << "Did not receive WWW-Authenticate reply to auth-test PROPFIND";
|
||||
}
|
||||
_propfindDone = true;
|
||||
checkBothDone();
|
||||
checkAllDone();
|
||||
});
|
||||
connect(oldFlowRequired, &JsonApiJob::jsonReceived, this, [this](const QJsonDocument &json, int statusCode) {
|
||||
if (statusCode == 200) {
|
||||
_resultOldFlow = LoginFlowV2;
|
||||
|
||||
auto data = json.object().value("ocs").toObject().value("data").toObject().value("capabilities").toObject();
|
||||
auto gs = data.value("globalscale");
|
||||
if (gs != QJsonValue::Undefined) {
|
||||
auto flow = gs.toObject().value("desktoplogin");
|
||||
if (flow != QJsonValue::Undefined) {
|
||||
if (flow.toInt() == 1) {
|
||||
_resultOldFlow = WebViewFlow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_oldFlowDone = true;
|
||||
checkAllDone();
|
||||
});
|
||||
|
||||
oldFlowRequired->start();
|
||||
}
|
||||
|
||||
void DetermineAuthTypeJob::checkBothDone()
|
||||
void DetermineAuthTypeJob::checkAllDone()
|
||||
{
|
||||
if (!_getDone || !_propfindDone)
|
||||
// Do not conitunue until eve
|
||||
if (!_getDone || !_propfindDone || !_oldFlowDone) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto result = _resultPropfind;
|
||||
// OAuth > Shib > Basic
|
||||
if (_resultGet == Shibboleth && result != OAuth)
|
||||
@@ -930,6 +963,11 @@ void DetermineAuthTypeJob::checkBothDone()
|
||||
result = LoginFlowV2;
|
||||
}
|
||||
|
||||
// If we determined that we need the webview flow (GS for example) then we switch to that
|
||||
if (_resultOldFlow == WebViewFlow) {
|
||||
result = WebViewFlow;
|
||||
}
|
||||
|
||||
qCInfo(lcDetermineAuthTypeJob) << "Auth type for" << _account->davUrl() << "is" << result;
|
||||
emit authType(result);
|
||||
deleteLater();
|
||||
|
||||
@@ -422,13 +422,15 @@ signals:
|
||||
void authType(AuthType);
|
||||
|
||||
private:
|
||||
void checkBothDone();
|
||||
void checkAllDone();
|
||||
|
||||
AccountPtr _account;
|
||||
AuthType _resultGet = Basic;
|
||||
AuthType _resultPropfind = Basic;
|
||||
AuthType _resultOldFlow = Basic;
|
||||
bool _getDone = false;
|
||||
bool _propfindDone = false;
|
||||
bool _oldFlowDone = false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -83,7 +83,7 @@ QString Theme::statusHeaderText(SyncResult::Status status) const
|
||||
resultStr = QCoreApplication::translate("theme", "Preparing to sync");
|
||||
break;
|
||||
case SyncResult::SyncAbortRequested:
|
||||
resultStr = QCoreApplication::translate("theme", "Aborting...");
|
||||
resultStr = QCoreApplication::translate("theme", "Aborting …");
|
||||
break;
|
||||
case SyncResult::Paused:
|
||||
resultStr = QCoreApplication::translate("theme", "Sync is paused");
|
||||
@@ -565,4 +565,76 @@ QString Theme::versionSwitchOutput() const
|
||||
return helpText;
|
||||
}
|
||||
|
||||
bool Theme::isDarkColor(const QColor &color)
|
||||
{
|
||||
// account for different sensitivity of the human eye to certain colors
|
||||
double treshold = 1.0 - (0.299 * color.red() + 0.587 * color.green() + 0.114 * color.blue()) / 255.0;
|
||||
return treshold > 0.5;
|
||||
}
|
||||
|
||||
QColor Theme::getBackgroundAwareLinkColor(const QColor &backgroundColor)
|
||||
{
|
||||
return QColor((isDarkColor(backgroundColor) ? QColor("#aabdff") : QGuiApplication::palette().color(QPalette::Link)));
|
||||
}
|
||||
|
||||
QColor Theme::getBackgroundAwareLinkColor()
|
||||
{
|
||||
return getBackgroundAwareLinkColor(QGuiApplication::palette().base().color());
|
||||
}
|
||||
|
||||
void Theme::replaceLinkColorStringBackgroundAware(QString &linkString, const QColor &backgroundColor)
|
||||
{
|
||||
linkString.replace(QRegularExpression("(<a href|<a style='color:#([a-zA-Z0-9]{6});' href)"), QString::fromLatin1("<a style='color:%1;' href").arg(getBackgroundAwareLinkColor(backgroundColor).name()));
|
||||
}
|
||||
|
||||
void Theme::replaceLinkColorStringBackgroundAware(QString &linkString)
|
||||
{
|
||||
replaceLinkColorStringBackgroundAware(linkString, QGuiApplication::palette().color(QPalette::Base));
|
||||
}
|
||||
|
||||
QIcon Theme::createColorAwareIcon(const QString &name, const QPalette &palette)
|
||||
{
|
||||
QImage img(name);
|
||||
QImage inverted(img);
|
||||
inverted.invertPixels(QImage::InvertRgb);
|
||||
|
||||
QIcon icon;
|
||||
if (Theme::isDarkColor(palette.color(QPalette::Base))) {
|
||||
icon.addPixmap(QPixmap::fromImage(inverted));
|
||||
} else {
|
||||
icon.addPixmap(QPixmap::fromImage(img));
|
||||
}
|
||||
if (Theme::isDarkColor(palette.color(QPalette::HighlightedText))) {
|
||||
icon.addPixmap(QPixmap::fromImage(img), QIcon::Normal, QIcon::On);
|
||||
} else {
|
||||
icon.addPixmap(QPixmap::fromImage(inverted), QIcon::Normal, QIcon::On);
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
|
||||
QIcon Theme::createColorAwareIcon(const QString &name)
|
||||
{
|
||||
return createColorAwareIcon(name, QGuiApplication::palette());
|
||||
}
|
||||
|
||||
QPixmap Theme::createColorAwarePixmap(const QString &name, const QPalette &palette)
|
||||
{
|
||||
QImage img(name);
|
||||
QImage inverted(img);
|
||||
inverted.invertPixels(QImage::InvertRgb);
|
||||
|
||||
QPixmap pixmap;
|
||||
if (Theme::isDarkColor(palette.color(QPalette::Base))) {
|
||||
pixmap = QPixmap::fromImage(inverted);
|
||||
} else {
|
||||
pixmap = QPixmap::fromImage(img);
|
||||
}
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
QPixmap Theme::createColorAwarePixmap(const QString &name)
|
||||
{
|
||||
return createColorAwarePixmap(name, QGuiApplication::palette());
|
||||
}
|
||||
|
||||
} // end namespace client
|
||||
|
||||
@@ -24,6 +24,7 @@ class QObject;
|
||||
class QPixmap;
|
||||
class QColor;
|
||||
class QPaintDevice;
|
||||
class QPalette;
|
||||
|
||||
namespace OCC {
|
||||
|
||||
@@ -355,6 +356,87 @@ public:
|
||||
* (actually 2019/09/13 only systray theming).
|
||||
*/
|
||||
virtual QIcon uiThemeIcon(const QString &iconName, bool uiHasDarkBg) const;
|
||||
|
||||
/**
|
||||
* @brief Perform a calculation to check if a colour is dark or light and accounts for different sensitivity of the human eye.
|
||||
*
|
||||
* @return True if the specified colour is dark.
|
||||
*
|
||||
* 2019/12/08: Moved here from SettingsDialog.
|
||||
*/
|
||||
static bool isDarkColor(const QColor &color);
|
||||
|
||||
/**
|
||||
* @brief Return the colour to be used for HTML links (e.g. used in QLabel), based on the current app palette or given colour (Dark-/Light-Mode switching).
|
||||
*
|
||||
* @return Background-aware colour for HTML links, based on the current app palette or given colour.
|
||||
*
|
||||
* 2019/12/08: Implemented for the Dark Mode on macOS, because the app palette can not account for that (Qt 5.12.5).
|
||||
*/
|
||||
static QColor getBackgroundAwareLinkColor(const QColor &backgroundColor);
|
||||
|
||||
/**
|
||||
* @brief Return the colour to be used for HTML links (e.g. used in QLabel), based on the current app palette (Dark-/Light-Mode switching).
|
||||
*
|
||||
* @return Background-aware colour for HTML links, based on the current app palette.
|
||||
*
|
||||
* 2019/12/08: Implemented for the Dark Mode on macOS, because the app palette can not account for that (Qt 5.12.5).
|
||||
*/
|
||||
static QColor getBackgroundAwareLinkColor();
|
||||
|
||||
/**
|
||||
* @brief Appends a CSS-style colour value to all HTML link tags in a given string, based on the current app palette or given colour (Dark-/Light-Mode switching).
|
||||
*
|
||||
* 2019/12/08: Implemented for the Dark Mode on macOS, because the app palette can not account for that (Qt 5.12.5).
|
||||
*
|
||||
* This way we also avoid having certain strings re-translated on Transifex.
|
||||
*/
|
||||
static void replaceLinkColorStringBackgroundAware(QString &linkString, const QColor &backgroundColor);
|
||||
|
||||
/**
|
||||
* @brief Appends a CSS-style colour value to all HTML link tags in a given string, based on the current app palette (Dark-/Light-Mode switching).
|
||||
*
|
||||
* 2019/12/08: Implemented for the Dark Mode on macOS, because the app palette can not account for that (Qt 5.12.5).
|
||||
*
|
||||
* This way we also avoid having certain strings re-translated on Transifex.
|
||||
*/
|
||||
static void replaceLinkColorStringBackgroundAware(QString &linkString);
|
||||
|
||||
/**
|
||||
* @brief Creates a colour-aware icon based on the specified palette's base colour.
|
||||
*
|
||||
* @return QIcon, colour-aware (inverted on dark backgrounds).
|
||||
*
|
||||
* 2019/12/09: Moved here from SettingsDialog.
|
||||
*/
|
||||
static QIcon createColorAwareIcon(const QString &name, const QPalette &palette);
|
||||
|
||||
/**
|
||||
* @brief Creates a colour-aware icon based on the app palette's base colour (Dark-/Light-Mode switching).
|
||||
*
|
||||
* @return QIcon, colour-aware (inverted on dark backgrounds).
|
||||
*
|
||||
* 2019/12/09: Moved here from SettingsDialog.
|
||||
*/
|
||||
static QIcon createColorAwareIcon(const QString &name);
|
||||
|
||||
/**
|
||||
* @brief Creates a colour-aware pixmap based on the specified palette's base colour.
|
||||
*
|
||||
* @return QPixmap, colour-aware (inverted on dark backgrounds).
|
||||
*
|
||||
* 2019/12/09: Adapted from createColorAwareIcon.
|
||||
*/
|
||||
static QPixmap createColorAwarePixmap(const QString &name, const QPalette &palette);
|
||||
|
||||
/**
|
||||
* @brief Creates a colour-aware pixmap based on the app palette's base colour (Dark-/Light-Mode switching).
|
||||
*
|
||||
* @return QPixmap, colour-aware (inverted on dark backgrounds).
|
||||
*
|
||||
* 2019/12/09: Adapted from createColorAwareIcon.
|
||||
*/
|
||||
static QPixmap createColorAwarePixmap(const QString &name);
|
||||
|
||||
protected:
|
||||
#ifndef TOKEN_AUTH_ONLY
|
||||
|
||||
@@ -12,10 +12,10 @@ include_directories(${CMAKE_SOURCE_DIR}/src
|
||||
${SQLITE3_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
include(owncloud_add_test.cmake)
|
||||
include(nextcloud_add_test.cmake)
|
||||
|
||||
owncloud_add_test(OwncloudPropagator "")
|
||||
owncloud_add_test(Updater "")
|
||||
nextcloud_add_test(NextcloudPropagator "")
|
||||
nextcloud_add_test(Updater "")
|
||||
|
||||
SET(FolderWatcher_SRC ../src/gui/folderwatcher.cpp)
|
||||
|
||||
@@ -29,49 +29,64 @@ IF( APPLE )
|
||||
list(APPEND FolderWatcher_SRC ../src/gui/folderwatcher_mac.cpp)
|
||||
list(APPEND FolderWatcher_SRC ../src/gui/socketapisocket_mac.mm)
|
||||
ENDIF()
|
||||
owncloud_add_test(NetrcParser ../src/cmd/netrcparser.cpp)
|
||||
owncloud_add_test(OwnSql "")
|
||||
owncloud_add_test(SyncJournalDB "")
|
||||
owncloud_add_test(SyncFileItem "")
|
||||
owncloud_add_test(ConcatUrl "")
|
||||
owncloud_add_test(XmlParse "")
|
||||
owncloud_add_test(ChecksumValidator "")
|
||||
nextcloud_add_test(NetrcParser ../src/cmd/netrcparser.cpp)
|
||||
nextcloud_add_test(OwnSql "")
|
||||
nextcloud_add_test(SyncJournalDB "")
|
||||
nextcloud_add_test(SyncFileItem "")
|
||||
nextcloud_add_test(ConcatUrl "")
|
||||
nextcloud_add_test(XmlParse "")
|
||||
nextcloud_add_test(ChecksumValidator "")
|
||||
|
||||
owncloud_add_test(ExcludedFiles "")
|
||||
nextcloud_add_test(ExcludedFiles "")
|
||||
|
||||
owncloud_add_test(FileSystem "")
|
||||
owncloud_add_test(Utility "")
|
||||
owncloud_add_test(SyncEngine "syncenginetestutils.h")
|
||||
owncloud_add_test(SyncMove "syncenginetestutils.h")
|
||||
owncloud_add_test(SyncConflict "syncenginetestutils.h")
|
||||
owncloud_add_test(SyncFileStatusTracker "syncenginetestutils.h")
|
||||
owncloud_add_test(ChunkingNg "syncenginetestutils.h")
|
||||
owncloud_add_test(UploadReset "syncenginetestutils.h")
|
||||
owncloud_add_test(AllFilesDeleted "syncenginetestutils.h")
|
||||
owncloud_add_test(Blacklist "syncenginetestutils.h")
|
||||
owncloud_add_test(FolderWatcher "${FolderWatcher_SRC}")
|
||||
nextcloud_add_test(FileSystem "")
|
||||
nextcloud_add_test(Utility "")
|
||||
nextcloud_add_test(SyncEngine "syncenginetestutils.h")
|
||||
nextcloud_add_test(SyncMove "syncenginetestutils.h")
|
||||
nextcloud_add_test(SyncConflict "syncenginetestutils.h")
|
||||
nextcloud_add_test(SyncFileStatusTracker "syncenginetestutils.h")
|
||||
nextcloud_add_test(ChunkingNg "syncenginetestutils.h")
|
||||
nextcloud_add_test(UploadReset "syncenginetestutils.h")
|
||||
nextcloud_add_test(AllFilesDeleted "syncenginetestutils.h")
|
||||
nextcloud_add_test(Blacklist "syncenginetestutils.h")
|
||||
nextcloud_add_test(FolderWatcher "${FolderWatcher_SRC}")
|
||||
|
||||
if( UNIX AND NOT APPLE )
|
||||
owncloud_add_test(InotifyWatcher "${FolderWatcher_SRC}")
|
||||
nextcloud_add_test(InotifyWatcher "${FolderWatcher_SRC}")
|
||||
endif(UNIX AND NOT APPLE)
|
||||
|
||||
owncloud_add_benchmark(LargeSync "syncenginetestutils.h")
|
||||
nextcloud_add_benchmark(LargeSync "syncenginetestutils.h")
|
||||
|
||||
SET(FolderMan_SRC ../src/gui/folderman.cpp)
|
||||
list(APPEND FolderMan_SRC ../src/gui/folder.cpp )
|
||||
list(APPEND FolderMan_SRC ../src/gui/socketapi.cpp )
|
||||
list(APPEND FolderMan_SRC ../src/gui/accountstate.cpp )
|
||||
list(APPEND FolderMan_SRC ../src/gui/syncrunfilelog.cpp )
|
||||
list(APPEND FolderMan_SRC ../src/gui/lockwatcher.cpp )
|
||||
list(APPEND FolderMan_SRC ../src/gui/guiutility.cpp )
|
||||
list(APPEND FolderMan_SRC ../src/gui/navigationpanehelper.cpp )
|
||||
list(APPEND FolderMan_SRC ../src/gui/connectionvalidator.cpp )
|
||||
list(APPEND FolderMan_SRC ../src/gui/clientproxy.cpp )
|
||||
list(APPEND FolderMan_SRC ../src/gui/accountstate.cpp )
|
||||
list(APPEND FolderMan_SRC ../src/gui/remotewipe.cpp )
|
||||
list(APPEND FolderMan_SRC ${FolderWatcher_SRC})
|
||||
list(APPEND FolderMan_SRC stub.cpp )
|
||||
owncloud_add_test(FolderMan "${FolderMan_SRC}")
|
||||
list(APPEND FolderMan_SRC stubfolderman.cpp )
|
||||
nextcloud_add_test(FolderMan "${FolderMan_SRC}")
|
||||
|
||||
owncloud_add_test(OAuth "syncenginetestutils.h;../src/gui/creds/oauth.cpp")
|
||||
SET(RemoteWipe_SRC ../src/gui/remotewipe.cpp)
|
||||
list(APPEND RemoteWipe_SRC ../src/gui/clientproxy.cpp )
|
||||
list(APPEND RemoteWipe_SRC ../src/gui/guiutility.cpp )
|
||||
list(APPEND RemoteWipe_SRC ../src/gui/connectionvalidator.cpp )
|
||||
list(APPEND RemoteWipe_SRC ../src/gui/accountstate.cpp )
|
||||
list(APPEND RemoteWipe_SRC ../src/gui/socketapi.cpp )
|
||||
list(APPEND RemoteWipe_SRC ../src/gui/folder.cpp )
|
||||
list(APPEND RemoteWipe_SRC ../src/gui/syncrunfilelog.cpp )
|
||||
list(APPEND RemoteWipe_SRC ../src/gui/folderwatcher_linux.cpp )
|
||||
list(APPEND RemoteWipe_SRC ../src/gui/folderwatcher.cpp )
|
||||
list(APPEND RemoteWipe_SRC ${RemoteWipe_SRC})
|
||||
list(APPEND RemoteWipe_SRC stubremotewipe.cpp )
|
||||
nextcloud_add_test(RemoteWipe "${RemoteWipe_SRC}")
|
||||
|
||||
nextcloud_add_test(OAuth "syncenginetestutils.h;../src/gui/creds/oauth.cpp")
|
||||
|
||||
configure_file(test_journal.db "${PROJECT_BINARY_DIR}/bin/test_journal.db" COPYONLY)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
find_package(Qt5 COMPONENTS Core Test Xml Network REQUIRED)
|
||||
|
||||
macro(owncloud_add_test test_class additional_cpp)
|
||||
macro(nextcloud_add_test test_class additional_cpp)
|
||||
set(CMAKE_AUTOMOC TRUE)
|
||||
set(OWNCLOUD_TEST_CLASS ${test_class})
|
||||
string(TOLOWER "${OWNCLOUD_TEST_CLASS}" OWNCLOUD_TEST_CLASS_LOWERCASE)
|
||||
@@ -19,7 +19,7 @@ macro(owncloud_add_test test_class additional_cpp)
|
||||
add_test(NAME ${OWNCLOUD_TEST_CLASS}Test COMMAND ${OWNCLOUD_TEST_CLASS}Test)
|
||||
endmacro()
|
||||
|
||||
macro(owncloud_add_benchmark test_class additional_cpp)
|
||||
macro(nextcloud_add_benchmark test_class additional_cpp)
|
||||
set(CMAKE_AUTOMOC TRUE)
|
||||
set(OWNCLOUD_TEST_CLASS ${test_class})
|
||||
string(TOLOWER "${OWNCLOUD_TEST_CLASS}" OWNCLOUD_TEST_CLASS_LOWERCASE)
|
||||
@@ -1,7 +1,11 @@
|
||||
// stub to prevent linker error
|
||||
#include "accountmanager.h"
|
||||
|
||||
OCC::AccountManager *OCC::AccountManager::instance() { return static_cast<AccountManager *>(new QObject); }
|
||||
void OCC::AccountManager::save(bool) { }
|
||||
void OCC::AccountManager::saveAccountState(AccountState *) { }
|
||||
void OCC::AccountManager::save(bool saveCredentials) { Q_UNUSED(saveCredentials); }
|
||||
void OCC::AccountManager::deleteAccount(AccountState *) { }
|
||||
void OCC::AccountManager::accountRemoved(OCC::AccountState*) { }
|
||||
OCC::AccountStatePtr OCC::AccountManager::account(const QString &){ return AccountStatePtr(); }
|
||||
void OCC::AccountManager::removeAccountFolders(OCC::AccountState*) { }
|
||||
const QMetaObject OCC::AccountManager::staticMetaObject = QObject::staticMetaObject;
|
||||
30
test/stubremotewipe.cpp
Normal file
30
test/stubremotewipe.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
// stub to prevent linker error
|
||||
#include "accountmanager.h"
|
||||
#include "accountstate.h"
|
||||
#include "socketapi.h"
|
||||
#include "folderman.h"
|
||||
|
||||
OCC::AccountManager *OCC::AccountManager::instance() { return static_cast<AccountManager *>(new QObject); }
|
||||
void OCC::AccountManager::save(bool) { }
|
||||
OCC::AccountState *OCC::AccountManager::addAccount(const AccountPtr& ac) { return new OCC::AccountState(ac); }
|
||||
void OCC::AccountManager::deleteAccount(AccountState *) { }
|
||||
void OCC::AccountManager::accountRemoved(OCC::AccountState*) { }
|
||||
OCC::AccountStatePtr OCC::AccountManager::account(const QString &){ return AccountStatePtr(); }
|
||||
const QMetaObject OCC::AccountManager::staticMetaObject = QObject::staticMetaObject;
|
||||
|
||||
OCC::FolderMan *OCC::FolderMan::instance() { return static_cast<FolderMan *>(new QObject); }
|
||||
void OCC::FolderMan::wipeDone(OCC::AccountState*, bool) { }
|
||||
OCC::Folder* OCC::FolderMan::addFolder(OCC::AccountState* as, OCC::FolderDefinition const &f) { return nullptr; }
|
||||
void OCC::FolderMan::slotWipeFolderForAccount(OCC::AccountState*) { }
|
||||
QString OCC::FolderMan::unescapeAlias(QString const&){ return QString(); }
|
||||
QString OCC::FolderMan::escapeAlias(QString const&){ return QString(); }
|
||||
void OCC::FolderMan::scheduleFolder(OCC::Folder*){ }
|
||||
OCC::SocketApi *OCC::FolderMan::socketApi(){ return new SocketApi; }
|
||||
OCC::Folder::Map OCC::FolderMan::map() { return OCC::Folder::Map(); }
|
||||
void OCC::FolderMan::setSyncEnabled(bool) { }
|
||||
void OCC::FolderMan::slotSyncOnceFileUnlocks(QString const&) { }
|
||||
void OCC::FolderMan::slotScheduleETagJob(QString const&, OCC::RequestEtagJob*){ }
|
||||
OCC::Folder *OCC::FolderMan::folderForPath(QString const&) { return nullptr; }
|
||||
OCC::Folder* OCC::FolderMan::folder(QString const&) { return nullptr; }
|
||||
void OCC::FolderMan::folderSyncStateChange(OCC::Folder*) { }
|
||||
const QMetaObject OCC::FolderMan::staticMetaObject = QObject::staticMetaObject;
|
||||
@@ -14,29 +14,10 @@
|
||||
#include "account.h"
|
||||
#include "accountstate.h"
|
||||
#include "configfile.h"
|
||||
#include "creds/httpcredentials.h"
|
||||
#include "testhelper.h"
|
||||
|
||||
using namespace OCC;
|
||||
|
||||
class HttpCredentialsTest : public HttpCredentials {
|
||||
public:
|
||||
HttpCredentialsTest(const QString& user, const QString& password)
|
||||
: HttpCredentials(user, password)
|
||||
{}
|
||||
|
||||
void askFromUser() Q_DECL_OVERRIDE {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
static FolderDefinition folderDefinition(const QString &path) {
|
||||
FolderDefinition d;
|
||||
d.localPath = path;
|
||||
d.targetPath = path;
|
||||
d.alias = path;
|
||||
return d;
|
||||
}
|
||||
|
||||
class HttpCredentials;
|
||||
|
||||
class TestFolderMan: public QObject
|
||||
{
|
||||
|
||||
@@ -146,7 +146,7 @@ private slots:
|
||||
mkdir(_rootPath + "/a0/b");
|
||||
mkdir(_rootPath + "/a0/b/c");
|
||||
touch(file);
|
||||
mv(_rootPath + "/a0 ", _rootPath + "/a");
|
||||
mv(_rootPath + "/a0", _rootPath + "/a");
|
||||
QVERIFY(waitForPathChanged(_rootPath + "/a/b/c/empty.txt"));
|
||||
}
|
||||
|
||||
|
||||
28
test/testhelper.h
Normal file
28
test/testhelper.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef TESTHELPER_H
|
||||
#define TESTHELPER_H
|
||||
|
||||
#include "folder.h"
|
||||
#include "creds/httpcredentials.h"
|
||||
|
||||
using namespace OCC;
|
||||
|
||||
class HttpCredentialsTest : public HttpCredentials {
|
||||
public:
|
||||
HttpCredentialsTest(const QString& user, const QString& password)
|
||||
: HttpCredentials(user, password)
|
||||
{}
|
||||
|
||||
void askFromUser() Q_DECL_OVERRIDE {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
static FolderDefinition folderDefinition(const QString &path) {
|
||||
FolderDefinition d;
|
||||
d.localPath = path;
|
||||
d.targetPath = path;
|
||||
d.alias = path;
|
||||
return d;
|
||||
}
|
||||
|
||||
#endif // TESTHELPER_H
|
||||
@@ -8,21 +8,21 @@
|
||||
#include <QDebug>
|
||||
|
||||
#include "propagatedownload.h"
|
||||
#include "owncloudpropagator_p.h"
|
||||
#include "nextcloudpropagator_p.h"
|
||||
|
||||
using namespace OCC;
|
||||
namespace OCC {
|
||||
QString OWNCLOUDSYNC_EXPORT createDownloadTmpFileName(const QString &previous);
|
||||
}
|
||||
|
||||
class TestOwncloudPropagator : public QObject
|
||||
class TestNextcloudPropagator : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void testUpdateErrorFromSession()
|
||||
{
|
||||
// OwncloudPropagator propagator( NULL, QLatin1String("test1"), QLatin1String("test2"), new ProgressDatabase);
|
||||
// NextcloudPropagator propagator( NULL, QLatin1String("test1"), QLatin1String("test2"), new ProgressDatabase);
|
||||
QVERIFY( true );
|
||||
}
|
||||
|
||||
@@ -78,5 +78,5 @@ private slots:
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_APPLESS_MAIN(TestOwncloudPropagator)
|
||||
#include "testowncloudpropagator.moc"
|
||||
QTEST_APPLESS_MAIN(TestNextcloudPropagator)
|
||||
#include "testnextcloudpropagator.moc"
|
||||
83
test/testremotewipe.cpp
Normal file
83
test/testremotewipe.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* This software is in the public domain, furnished "as is", without technical
|
||||
* support, and with no warranty, express or implied, as to its usefulness for
|
||||
* any purpose.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <qglobal.h>
|
||||
#include <QTemporaryDir>
|
||||
#include <QtTest>
|
||||
|
||||
#include "remotewipe.h"
|
||||
|
||||
#include "common/utility.h"
|
||||
#include "folderman.h"
|
||||
#include "account.h"
|
||||
#include "accountstate.h"
|
||||
#include "configfile.h"
|
||||
|
||||
#include "testhelper.h"
|
||||
|
||||
using namespace OCC;
|
||||
|
||||
class TestRemoteWipe: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
// TODO
|
||||
void testWipe(){
|
||||
// QTemporaryDir dir;
|
||||
// ConfigFile::setConfDir(dir.path()); // we don't want to pollute the user's config file
|
||||
// QVERIFY(dir.isValid());
|
||||
|
||||
// QDir dirToRemove(dir.path());
|
||||
// QVERIFY(dirToRemove.mkpath("nextcloud"));
|
||||
|
||||
// QString dirPath = dirToRemove.canonicalPath();
|
||||
|
||||
// AccountPtr account = Account::create();
|
||||
// QVERIFY(account);
|
||||
|
||||
// auto manager = AccountManager::instance();
|
||||
// QVERIFY(manager);
|
||||
|
||||
// AccountState *newAccountState = manager->addAccount(account);
|
||||
// manager->save();
|
||||
// QVERIFY(newAccountState);
|
||||
|
||||
// QUrl url("http://example.de");
|
||||
// HttpCredentialsTest *cred = new HttpCredentialsTest("testuser", "secret");
|
||||
// account->setCredentials(cred);
|
||||
// account->setUrl( url );
|
||||
|
||||
// FolderMan *folderman = FolderMan::instance();
|
||||
// folderman->addFolder(newAccountState, folderDefinition(dirPath + "/sub/nextcloud/"));
|
||||
|
||||
// // check if account exists
|
||||
// qDebug() << "Does account exists?!";
|
||||
// QVERIFY(!account->id().isEmpty());
|
||||
|
||||
// manager->deleteAccount(newAccountState);
|
||||
// manager->save();
|
||||
|
||||
// // check if account exists
|
||||
// qDebug() << "Does account exists yet?!";
|
||||
// QVERIFY(account);
|
||||
|
||||
// // check if folder exists
|
||||
// QVERIFY(dirToRemove.exists());
|
||||
|
||||
// // remote folders
|
||||
// qDebug() << "Removing folder for account " << newAccountState->account()->url();
|
||||
|
||||
// folderman->slotWipeFolderForAccount(newAccountState);
|
||||
|
||||
// // check if folders dont exist anymore
|
||||
// QCOMPARE(dirToRemove.exists(), false);
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_APPLESS_MAIN(TestRemoteWipe)
|
||||
#include "testremotewipe.moc"
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user