This commit is contained in:
@@ -94,6 +94,8 @@
|
|||||||
"Discovered": "Discovered",
|
"Discovered": "Discovered",
|
||||||
"Discovery": "Discovery",
|
"Discovery": "Discovery",
|
||||||
"Discovery Failures": "Discovery Failures",
|
"Discovery Failures": "Discovery Failures",
|
||||||
|
"Dismiss": "Dismiss",
|
||||||
|
"Do not add it to the ignore list, so this notification may recurr.": "Do not add it to the ignore list, so this notification may recurr.",
|
||||||
"Do not restore": "Do not restore",
|
"Do not restore": "Do not restore",
|
||||||
"Do not restore all": "Do not restore all",
|
"Do not restore all": "Do not restore all",
|
||||||
"Do you want to enable watching for changes for all your folders?": "Do you want to enable watching for changes for all your folders?",
|
"Do you want to enable watching for changes for all your folders?": "Do you want to enable watching for changes for all your folders?",
|
||||||
@@ -227,6 +229,7 @@
|
|||||||
"Periodic scanning at given interval and disabled watching for changes": "Periodic scanning at given interval and disabled watching for changes",
|
"Periodic scanning at given interval and disabled watching for changes": "Periodic scanning at given interval and disabled watching for changes",
|
||||||
"Periodic scanning at given interval and enabled watching for changes": "Periodic scanning at given interval and enabled watching for changes",
|
"Periodic scanning at given interval and enabled watching for changes": "Periodic scanning at given interval and enabled watching for changes",
|
||||||
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:",
|
"Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:": "Periodic scanning at given interval and failed setting up watching for changes, retrying every 1m:",
|
||||||
|
"Permanently add it to the ignore list, suppressing further notifications.": "Permanently add it to the ignore list, suppressing further notifications.",
|
||||||
"Permissions": "Permissions",
|
"Permissions": "Permissions",
|
||||||
"Please consult the release notes before performing a major upgrade.": "Please consult the release notes before performing a major upgrade.",
|
"Please consult the release notes before performing a major upgrade.": "Please consult the release notes before performing a major upgrade.",
|
||||||
"Please set a GUI Authentication User and Password in the Settings dialog.": "Please set a GUI Authentication User and Password in the Settings dialog.",
|
"Please set a GUI Authentication User and Password in the Settings dialog.": "Please set a GUI Authentication User and Password in the Settings dialog.",
|
||||||
|
|||||||
@@ -209,10 +209,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="panel-footer clearfix">
|
<div class="panel-footer clearfix">
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
|
<button type="button" class="btn btn-sm btn-default" ng-click="dismissPendingDevice(deviceID)" tooltip data-original-title="{{'Do not add it to the ignore list, so this notification may recurr.' | translate}}">
|
||||||
|
<span class="far fa-clock"></span> <span translate>Dismiss</span>
|
||||||
|
</button>
|
||||||
<button type="button" class="btn btn-sm btn-success" ng-click="addDevice(deviceID, pendingDevice.name)">
|
<button type="button" class="btn btn-sm btn-success" ng-click="addDevice(deviceID, pendingDevice.name)">
|
||||||
<span class="fas fa-plus"></span> <span translate>Add Device</span>
|
<span class="fas fa-plus"></span> <span translate>Add Device</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-sm btn-danger" ng-click="ignoreDevice(deviceID, pendingDevice)">
|
<button type="button" class="btn btn-sm btn-danger" ng-click="ignoreDevice(deviceID, pendingDevice)" tooltip data-original-title="{{'Permanently add it to the ignore list, suppressing further notifications.' | translate}}">
|
||||||
<span class="fas fa-times"></span> <span translate>Ignore</span>
|
<span class="fas fa-times"></span> <span translate>Ignore</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -250,13 +253,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="panel-footer clearfix">
|
<div class="panel-footer clearfix">
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
|
<button type="button" class="btn btn-sm btn-default" ng-click="dismissPendingFolder(folderID, deviceID)" tooltip data-original-title="{{'Do not add it to the ignore list, so this notification may recurr.' | translate}}">
|
||||||
|
<span class="far fa-clock"></span> <span translate>Dismiss</span>
|
||||||
|
</button>
|
||||||
<button type="button" class="btn btn-sm btn-success" ng-click="addFolderAndShare(folderID, pendingFolder, deviceID)" ng-if="!folders[folderID]">
|
<button type="button" class="btn btn-sm btn-success" ng-click="addFolderAndShare(folderID, pendingFolder, deviceID)" ng-if="!folders[folderID]">
|
||||||
<span class="fas fa-check"></span> <span translate>Add</span>
|
<span class="fas fa-check"></span> <span translate>Add</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-sm btn-success" ng-click="shareFolderWithDevice(folderID, deviceID)" ng-if="folders[folderID]">
|
<button type="button" class="btn btn-sm btn-success" ng-click="shareFolderWithDevice(folderID, deviceID)" ng-if="folders[folderID]">
|
||||||
<span class="fas fa-check"></span> <span translate>Share</span>
|
<span class="fas fa-check"></span> <span translate>Share</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-sm btn-danger" ng-click="ignoreFolder(deviceID, folderID, offeringDevice)">
|
<button type="button" class="btn btn-sm btn-danger" ng-click="ignoreFolder(deviceID, folderID, offeringDevice)" tooltip data-original-title="{{'Permanently add it to the ignore list, suppressing further notifications.' | translate}}">
|
||||||
<span class="fas fa-times"></span> <span translate>Ignore</span>
|
<span class="fas fa-times"></span> <span translate>Ignore</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1749,6 +1749,10 @@ angular.module('syncthing.core')
|
|||||||
$scope.saveConfig();
|
$scope.saveConfig();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.dismissPendingDevice = function (deviceID) {
|
||||||
|
$http.delete(urlbase + '/cluster/pending/devices?device=' + encodeURIComponent(deviceID));
|
||||||
|
};
|
||||||
|
|
||||||
$scope.unignoreDeviceFromTemporaryConfig = function (ignoredDevice) {
|
$scope.unignoreDeviceFromTemporaryConfig = function (ignoredDevice) {
|
||||||
$scope.tmpRemoteIgnoredDevices = $scope.tmpRemoteIgnoredDevices.filter(function (existingIgnoredDevice) {
|
$scope.tmpRemoteIgnoredDevices = $scope.tmpRemoteIgnoredDevices.filter(function (existingIgnoredDevice) {
|
||||||
return ignoredDevice.deviceID !== existingIgnoredDevice.deviceID;
|
return ignoredDevice.deviceID !== existingIgnoredDevice.deviceID;
|
||||||
@@ -2220,6 +2224,11 @@ angular.module('syncthing.core')
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.dismissPendingFolder = function (folderID, deviceID) {
|
||||||
|
$http.delete(urlbase + '/cluster/pending/folders?folder=' + encodeURIComponent(folderID)
|
||||||
|
+ '&device=' + encodeURIComponent(deviceID));
|
||||||
|
};
|
||||||
|
|
||||||
$scope.sharesFolder = function (folderCfg) {
|
$scope.sharesFolder = function (folderCfg) {
|
||||||
var names = [];
|
var names = [];
|
||||||
folderCfg.devices.forEach(function (device) {
|
folderCfg.devices.forEach(function (device) {
|
||||||
|
|||||||
@@ -291,6 +291,10 @@ func (s *service) Serve(ctx context.Context) error {
|
|||||||
restMux.HandlerFunc(http.MethodPost, "/rest/system/resume", s.makeDevicePauseHandler(false)) // [device]
|
restMux.HandlerFunc(http.MethodPost, "/rest/system/resume", s.makeDevicePauseHandler(false)) // [device]
|
||||||
restMux.HandlerFunc(http.MethodPost, "/rest/system/debug", s.postSystemDebug) // [enable] [disable]
|
restMux.HandlerFunc(http.MethodPost, "/rest/system/debug", s.postSystemDebug) // [enable] [disable]
|
||||||
|
|
||||||
|
// The DELETE handlers
|
||||||
|
restMux.HandlerFunc(http.MethodDelete, "/rest/cluster/pending/devices", s.deletePendingDevices) // device
|
||||||
|
restMux.HandlerFunc(http.MethodDelete, "/rest/cluster/pending/folders", s.deletePendingFolders) // folder [device]
|
||||||
|
|
||||||
// Config endpoints
|
// Config endpoints
|
||||||
|
|
||||||
configBuilder := &configMuxBuilder{
|
configBuilder := &configMuxBuilder{
|
||||||
@@ -632,6 +636,21 @@ func (s *service) getPendingDevices(w http.ResponseWriter, r *http.Request) {
|
|||||||
sendJSON(w, devices)
|
sendJSON(w, devices)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *service) deletePendingDevices(w http.ResponseWriter, r *http.Request) {
|
||||||
|
qs := r.URL.Query()
|
||||||
|
|
||||||
|
device := qs.Get("device")
|
||||||
|
deviceID, err := protocol.DeviceIDFromString(device)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.model.DismissPendingDevice(deviceID); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *service) getPendingFolders(w http.ResponseWriter, r *http.Request) {
|
func (s *service) getPendingFolders(w http.ResponseWriter, r *http.Request) {
|
||||||
qs := r.URL.Query()
|
qs := r.URL.Query()
|
||||||
|
|
||||||
@@ -650,6 +669,22 @@ func (s *service) getPendingFolders(w http.ResponseWriter, r *http.Request) {
|
|||||||
sendJSON(w, folders)
|
sendJSON(w, folders)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *service) deletePendingFolders(w http.ResponseWriter, r *http.Request) {
|
||||||
|
qs := r.URL.Query()
|
||||||
|
|
||||||
|
device := qs.Get("device")
|
||||||
|
deviceID, err := protocol.DeviceIDFromString(device)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
folderID := qs.Get("folder")
|
||||||
|
|
||||||
|
if err := s.model.DismissPendingFolder(deviceID, folderID); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *service) restPing(w http.ResponseWriter, r *http.Request) {
|
func (s *service) restPing(w http.ResponseWriter, r *http.Request) {
|
||||||
sendJSON(w, map[string]string{"ping": "pong"})
|
sendJSON(w, map[string]string{"ping": "pong"})
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-6
@@ -26,11 +26,13 @@ func (db *Lowlevel) AddOrUpdatePendingDevice(device protocol.DeviceID, name, add
|
|||||||
return db.Put(key, bs)
|
return db.Put(key, bs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *Lowlevel) RemovePendingDevice(device protocol.DeviceID) {
|
func (db *Lowlevel) RemovePendingDevice(device protocol.DeviceID) error {
|
||||||
key := db.keyer.GeneratePendingDeviceKey(nil, device[:])
|
key := db.keyer.GeneratePendingDeviceKey(nil, device[:])
|
||||||
if err := db.Delete(key); err != nil {
|
if err := db.Delete(key); err != nil {
|
||||||
l.Warnf("Failed to remove pending device entry: %v", err)
|
l.Warnf("Failed to remove pending device entry: %v", err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PendingDevices enumerates all entries. Invalid ones are dropped from the database
|
// PendingDevices enumerates all entries. Invalid ones are dropped from the database
|
||||||
@@ -79,32 +81,35 @@ func (db *Lowlevel) AddOrUpdatePendingFolder(id string, of ObservedFolder, devic
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RemovePendingFolderForDevice removes entries for specific folder / device combinations.
|
// RemovePendingFolderForDevice removes entries for specific folder / device combinations.
|
||||||
func (db *Lowlevel) RemovePendingFolderForDevice(id string, device protocol.DeviceID) {
|
func (db *Lowlevel) RemovePendingFolderForDevice(id string, device protocol.DeviceID) error {
|
||||||
key, err := db.keyer.GeneratePendingFolderKey(nil, device[:], []byte(id))
|
key, err := db.keyer.GeneratePendingFolderKey(nil, device[:], []byte(id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
if err := db.Delete(key); err != nil {
|
if err := db.Delete(key); err != nil {
|
||||||
l.Warnf("Failed to remove pending folder entry: %v", err)
|
l.Warnf("Failed to remove pending folder entry: %v", err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemovePendingFolder removes all entries matching a specific folder ID.
|
// RemovePendingFolder removes all entries matching a specific folder ID.
|
||||||
func (db *Lowlevel) RemovePendingFolder(id string) {
|
func (db *Lowlevel) RemovePendingFolder(id string) error {
|
||||||
iter, err := db.NewPrefixIterator([]byte{KeyTypePendingFolder})
|
iter, err := db.NewPrefixIterator([]byte{KeyTypePendingFolder})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Infof("Could not iterate through pending folder entries: %v", err)
|
l.Infof("Could not iterate through pending folder entries: %v", err)
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
defer iter.Release()
|
defer iter.Release()
|
||||||
for iter.Next() {
|
for iter.Next() {
|
||||||
if id != string(db.keyer.FolderFromPendingFolderKey(iter.Key())) {
|
if id != string(db.keyer.FolderFromPendingFolderKey(iter.Key())) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := db.Delete(iter.Key()); err != nil {
|
if err = db.Delete(iter.Key()); err != nil {
|
||||||
l.Warnf("Failed to remove pending folder entry: %v", err)
|
l.Warnf("Failed to remove pending folder entry: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Consolidated information about a pending folder
|
// Consolidated information about a pending folder
|
||||||
|
|||||||
@@ -177,6 +177,29 @@ type Model struct {
|
|||||||
result1 map[protocol.DeviceID]stats.DeviceStatistics
|
result1 map[protocol.DeviceID]stats.DeviceStatistics
|
||||||
result2 error
|
result2 error
|
||||||
}
|
}
|
||||||
|
DismissPendingDeviceStub func(protocol.DeviceID) error
|
||||||
|
dismissPendingDeviceMutex sync.RWMutex
|
||||||
|
dismissPendingDeviceArgsForCall []struct {
|
||||||
|
arg1 protocol.DeviceID
|
||||||
|
}
|
||||||
|
dismissPendingDeviceReturns struct {
|
||||||
|
result1 error
|
||||||
|
}
|
||||||
|
dismissPendingDeviceReturnsOnCall map[int]struct {
|
||||||
|
result1 error
|
||||||
|
}
|
||||||
|
DismissPendingFolderStub func(protocol.DeviceID, string) error
|
||||||
|
dismissPendingFolderMutex sync.RWMutex
|
||||||
|
dismissPendingFolderArgsForCall []struct {
|
||||||
|
arg1 protocol.DeviceID
|
||||||
|
arg2 string
|
||||||
|
}
|
||||||
|
dismissPendingFolderReturns struct {
|
||||||
|
result1 error
|
||||||
|
}
|
||||||
|
dismissPendingFolderReturnsOnCall map[int]struct {
|
||||||
|
result1 error
|
||||||
|
}
|
||||||
DownloadProgressStub func(protocol.DeviceID, string, []protocol.FileDownloadProgressUpdate) error
|
DownloadProgressStub func(protocol.DeviceID, string, []protocol.FileDownloadProgressUpdate) error
|
||||||
downloadProgressMutex sync.RWMutex
|
downloadProgressMutex sync.RWMutex
|
||||||
downloadProgressArgsForCall []struct {
|
downloadProgressArgsForCall []struct {
|
||||||
@@ -1332,6 +1355,129 @@ func (fake *Model) DeviceStatisticsReturnsOnCall(i int, result1 map[protocol.Dev
|
|||||||
}{result1, result2}
|
}{result1, result2}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fake *Model) DismissPendingDevice(arg1 protocol.DeviceID) error {
|
||||||
|
fake.dismissPendingDeviceMutex.Lock()
|
||||||
|
ret, specificReturn := fake.dismissPendingDeviceReturnsOnCall[len(fake.dismissPendingDeviceArgsForCall)]
|
||||||
|
fake.dismissPendingDeviceArgsForCall = append(fake.dismissPendingDeviceArgsForCall, struct {
|
||||||
|
arg1 protocol.DeviceID
|
||||||
|
}{arg1})
|
||||||
|
stub := fake.DismissPendingDeviceStub
|
||||||
|
fakeReturns := fake.dismissPendingDeviceReturns
|
||||||
|
fake.recordInvocation("DismissPendingDevice", []interface{}{arg1})
|
||||||
|
fake.dismissPendingDeviceMutex.Unlock()
|
||||||
|
if stub != nil {
|
||||||
|
return stub(arg1)
|
||||||
|
}
|
||||||
|
if specificReturn {
|
||||||
|
return ret.result1
|
||||||
|
}
|
||||||
|
return fakeReturns.result1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *Model) DismissPendingDeviceCallCount() int {
|
||||||
|
fake.dismissPendingDeviceMutex.RLock()
|
||||||
|
defer fake.dismissPendingDeviceMutex.RUnlock()
|
||||||
|
return len(fake.dismissPendingDeviceArgsForCall)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *Model) DismissPendingDeviceCalls(stub func(protocol.DeviceID) error) {
|
||||||
|
fake.dismissPendingDeviceMutex.Lock()
|
||||||
|
defer fake.dismissPendingDeviceMutex.Unlock()
|
||||||
|
fake.DismissPendingDeviceStub = stub
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *Model) DismissPendingDeviceArgsForCall(i int) protocol.DeviceID {
|
||||||
|
fake.dismissPendingDeviceMutex.RLock()
|
||||||
|
defer fake.dismissPendingDeviceMutex.RUnlock()
|
||||||
|
argsForCall := fake.dismissPendingDeviceArgsForCall[i]
|
||||||
|
return argsForCall.arg1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *Model) DismissPendingDeviceReturns(result1 error) {
|
||||||
|
fake.dismissPendingDeviceMutex.Lock()
|
||||||
|
defer fake.dismissPendingDeviceMutex.Unlock()
|
||||||
|
fake.DismissPendingDeviceStub = nil
|
||||||
|
fake.dismissPendingDeviceReturns = struct {
|
||||||
|
result1 error
|
||||||
|
}{result1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *Model) DismissPendingDeviceReturnsOnCall(i int, result1 error) {
|
||||||
|
fake.dismissPendingDeviceMutex.Lock()
|
||||||
|
defer fake.dismissPendingDeviceMutex.Unlock()
|
||||||
|
fake.DismissPendingDeviceStub = nil
|
||||||
|
if fake.dismissPendingDeviceReturnsOnCall == nil {
|
||||||
|
fake.dismissPendingDeviceReturnsOnCall = make(map[int]struct {
|
||||||
|
result1 error
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fake.dismissPendingDeviceReturnsOnCall[i] = struct {
|
||||||
|
result1 error
|
||||||
|
}{result1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *Model) DismissPendingFolder(arg1 protocol.DeviceID, arg2 string) error {
|
||||||
|
fake.dismissPendingFolderMutex.Lock()
|
||||||
|
ret, specificReturn := fake.dismissPendingFolderReturnsOnCall[len(fake.dismissPendingFolderArgsForCall)]
|
||||||
|
fake.dismissPendingFolderArgsForCall = append(fake.dismissPendingFolderArgsForCall, struct {
|
||||||
|
arg1 protocol.DeviceID
|
||||||
|
arg2 string
|
||||||
|
}{arg1, arg2})
|
||||||
|
stub := fake.DismissPendingFolderStub
|
||||||
|
fakeReturns := fake.dismissPendingFolderReturns
|
||||||
|
fake.recordInvocation("DismissPendingFolder", []interface{}{arg1, arg2})
|
||||||
|
fake.dismissPendingFolderMutex.Unlock()
|
||||||
|
if stub != nil {
|
||||||
|
return stub(arg1, arg2)
|
||||||
|
}
|
||||||
|
if specificReturn {
|
||||||
|
return ret.result1
|
||||||
|
}
|
||||||
|
return fakeReturns.result1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *Model) DismissPendingFolderCallCount() int {
|
||||||
|
fake.dismissPendingFolderMutex.RLock()
|
||||||
|
defer fake.dismissPendingFolderMutex.RUnlock()
|
||||||
|
return len(fake.dismissPendingFolderArgsForCall)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *Model) DismissPendingFolderCalls(stub func(protocol.DeviceID, string) error) {
|
||||||
|
fake.dismissPendingFolderMutex.Lock()
|
||||||
|
defer fake.dismissPendingFolderMutex.Unlock()
|
||||||
|
fake.DismissPendingFolderStub = stub
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *Model) DismissPendingFolderArgsForCall(i int) (protocol.DeviceID, string) {
|
||||||
|
fake.dismissPendingFolderMutex.RLock()
|
||||||
|
defer fake.dismissPendingFolderMutex.RUnlock()
|
||||||
|
argsForCall := fake.dismissPendingFolderArgsForCall[i]
|
||||||
|
return argsForCall.arg1, argsForCall.arg2
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *Model) DismissPendingFolderReturns(result1 error) {
|
||||||
|
fake.dismissPendingFolderMutex.Lock()
|
||||||
|
defer fake.dismissPendingFolderMutex.Unlock()
|
||||||
|
fake.DismissPendingFolderStub = nil
|
||||||
|
fake.dismissPendingFolderReturns = struct {
|
||||||
|
result1 error
|
||||||
|
}{result1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fake *Model) DismissPendingFolderReturnsOnCall(i int, result1 error) {
|
||||||
|
fake.dismissPendingFolderMutex.Lock()
|
||||||
|
defer fake.dismissPendingFolderMutex.Unlock()
|
||||||
|
fake.DismissPendingFolderStub = nil
|
||||||
|
if fake.dismissPendingFolderReturnsOnCall == nil {
|
||||||
|
fake.dismissPendingFolderReturnsOnCall = make(map[int]struct {
|
||||||
|
result1 error
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fake.dismissPendingFolderReturnsOnCall[i] = struct {
|
||||||
|
result1 error
|
||||||
|
}{result1}
|
||||||
|
}
|
||||||
|
|
||||||
func (fake *Model) DownloadProgress(arg1 protocol.DeviceID, arg2 string, arg3 []protocol.FileDownloadProgressUpdate) error {
|
func (fake *Model) DownloadProgress(arg1 protocol.DeviceID, arg2 string, arg3 []protocol.FileDownloadProgressUpdate) error {
|
||||||
var arg3Copy []protocol.FileDownloadProgressUpdate
|
var arg3Copy []protocol.FileDownloadProgressUpdate
|
||||||
if arg3 != nil {
|
if arg3 != nil {
|
||||||
@@ -3254,6 +3400,10 @@ func (fake *Model) Invocations() map[string][][]interface{} {
|
|||||||
defer fake.delayScanMutex.RUnlock()
|
defer fake.delayScanMutex.RUnlock()
|
||||||
fake.deviceStatisticsMutex.RLock()
|
fake.deviceStatisticsMutex.RLock()
|
||||||
defer fake.deviceStatisticsMutex.RUnlock()
|
defer fake.deviceStatisticsMutex.RUnlock()
|
||||||
|
fake.dismissPendingDeviceMutex.RLock()
|
||||||
|
defer fake.dismissPendingDeviceMutex.RUnlock()
|
||||||
|
fake.dismissPendingFolderMutex.RLock()
|
||||||
|
defer fake.dismissPendingFolderMutex.RUnlock()
|
||||||
fake.downloadProgressMutex.RLock()
|
fake.downloadProgressMutex.RLock()
|
||||||
defer fake.downloadProgressMutex.RUnlock()
|
defer fake.downloadProgressMutex.RUnlock()
|
||||||
fake.folderErrorsMutex.RLock()
|
fake.folderErrorsMutex.RLock()
|
||||||
|
|||||||
+78
-15
@@ -107,6 +107,8 @@ type Model interface {
|
|||||||
|
|
||||||
PendingDevices() (map[protocol.DeviceID]db.ObservedDevice, error)
|
PendingDevices() (map[protocol.DeviceID]db.ObservedDevice, error)
|
||||||
PendingFolders(device protocol.DeviceID) (map[string]db.PendingFolder, error)
|
PendingFolders(device protocol.DeviceID) (map[string]db.PendingFolder, error)
|
||||||
|
DismissPendingDevice(device protocol.DeviceID) error
|
||||||
|
DismissPendingFolder(device protocol.DeviceID, folder string) error
|
||||||
|
|
||||||
StartDeadlockDetector(timeout time.Duration)
|
StartDeadlockDetector(timeout time.Duration)
|
||||||
GlobalDirectoryTree(folder, prefix string, levels int, dirsOnly bool) ([]*TreeEntry, error)
|
GlobalDirectoryTree(folder, prefix string, levels int, dirsOnly bool) ([]*TreeEntry, error)
|
||||||
@@ -1374,17 +1376,18 @@ func (m *model) ccHandleFolders(folders []protocol.Folder, deviceCfg config.Devi
|
|||||||
}
|
}
|
||||||
|
|
||||||
indexHandlers.RemoveAllExcept(seenFolders)
|
indexHandlers.RemoveAllExcept(seenFolders)
|
||||||
|
expiredPendingList := make([]map[string]string, 0, len(expiredPending))
|
||||||
for folder := range expiredPending {
|
for folder := range expiredPending {
|
||||||
m.db.RemovePendingFolderForDevice(folder, deviceID)
|
if err = m.db.RemovePendingFolderForDevice(folder, deviceID); err != nil {
|
||||||
}
|
// Nothing we can fix; logged from DB already
|
||||||
if len(updatedPending) > 0 || len(expiredPending) > 0 {
|
continue
|
||||||
expiredPendingList := make([]map[string]string, 0, len(expiredPending))
|
|
||||||
for folderID := range expiredPending {
|
|
||||||
expiredPendingList = append(expiredPendingList, map[string]string{
|
|
||||||
"folderID": folderID,
|
|
||||||
"deviceID": deviceID.String(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
expiredPendingList = append(expiredPendingList, map[string]string{
|
||||||
|
"folderID": folder,
|
||||||
|
"deviceID": deviceID.String(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if len(updatedPending) > 0 || len(expiredPendingList) > 0 {
|
||||||
m.evLogger.Log(events.PendingFoldersChanged, map[string]interface{}{
|
m.evLogger.Log(events.PendingFoldersChanged, map[string]interface{}{
|
||||||
"added": updatedPending,
|
"added": updatedPending,
|
||||||
"removed": expiredPendingList,
|
"removed": expiredPendingList,
|
||||||
@@ -2947,10 +2950,13 @@ func (m *model) cleanPending(existingDevices map[protocol.DeviceID]config.Device
|
|||||||
// folders as well, assuming the folder is no longer of interest
|
// folders as well, assuming the folder is no longer of interest
|
||||||
// at all (but might become pending again).
|
// at all (but might become pending again).
|
||||||
l.Debugf("Discarding pending removed folder %v from all devices", folderID)
|
l.Debugf("Discarding pending removed folder %v from all devices", folderID)
|
||||||
m.db.RemovePendingFolder(folderID)
|
if err := m.db.RemovePendingFolder(folderID); err != nil {
|
||||||
removedPendingFolders = append(removedPendingFolders, map[string]string{
|
// Nothing we can fix; logged from DB already
|
||||||
"folderID": folderID,
|
} else {
|
||||||
})
|
removedPendingFolders = append(removedPendingFolders, map[string]string{
|
||||||
|
"folderID": folderID,
|
||||||
|
})
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for deviceID := range pf.OfferedBy {
|
for deviceID := range pf.OfferedBy {
|
||||||
@@ -2969,7 +2975,10 @@ func (m *model) cleanPending(existingDevices map[protocol.DeviceID]config.Device
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
removeFolderForDevice:
|
removeFolderForDevice:
|
||||||
m.db.RemovePendingFolderForDevice(folderID, deviceID)
|
if err := m.db.RemovePendingFolderForDevice(folderID, deviceID); err != nil {
|
||||||
|
// Nothing we can fix; logged from DB already
|
||||||
|
continue
|
||||||
|
}
|
||||||
removedPendingFolders = append(removedPendingFolders, map[string]string{
|
removedPendingFolders = append(removedPendingFolders, map[string]string{
|
||||||
"folderID": folderID,
|
"folderID": folderID,
|
||||||
"deviceID": deviceID.String(),
|
"deviceID": deviceID.String(),
|
||||||
@@ -2999,7 +3008,10 @@ func (m *model) cleanPending(existingDevices map[protocol.DeviceID]config.Device
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
removeDevice:
|
removeDevice:
|
||||||
m.db.RemovePendingDevice(deviceID)
|
if err := m.db.RemovePendingDevice(deviceID); err != nil {
|
||||||
|
// Nothing we can fix; logged from DB already
|
||||||
|
continue
|
||||||
|
}
|
||||||
removedPendingDevices = append(removedPendingDevices, map[string]string{
|
removedPendingDevices = append(removedPendingDevices, map[string]string{
|
||||||
"deviceID": deviceID.String(),
|
"deviceID": deviceID.String(),
|
||||||
})
|
})
|
||||||
@@ -3041,6 +3053,57 @@ func (m *model) PendingFolders(device protocol.DeviceID) (map[string]db.PendingF
|
|||||||
return m.db.PendingFoldersForDevice(device)
|
return m.db.PendingFoldersForDevice(device)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DismissPendingDevices removes the record of a specific pending device.
|
||||||
|
func (m *model) DismissPendingDevice(device protocol.DeviceID) error {
|
||||||
|
l.Debugf("Discarding pending device %v", device)
|
||||||
|
err := m.db.RemovePendingDevice(device)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
removedPendingDevices := []map[string]string{
|
||||||
|
{"deviceID": device.String()},
|
||||||
|
}
|
||||||
|
m.evLogger.Log(events.PendingDevicesChanged, map[string]interface{}{
|
||||||
|
"removed": removedPendingDevices,
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DismissPendingFolders removes records of pending folders. Either a specific folder /
|
||||||
|
// device combination, or all matching a specific folder ID if the device argument is
|
||||||
|
// specified as EmptyDeviceID.
|
||||||
|
func (m *model) DismissPendingFolder(device protocol.DeviceID, folder string) error {
|
||||||
|
var removedPendingFolders []map[string]string
|
||||||
|
if device == protocol.EmptyDeviceID {
|
||||||
|
l.Debugf("Discarding pending removed folder %s from all devices", folder)
|
||||||
|
err := m.db.RemovePendingFolder(folder)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
removedPendingFolders = []map[string]string{
|
||||||
|
{"folderID": folder},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
l.Debugf("Discarding pending folder %s from device %v", folder, device)
|
||||||
|
err := m.db.RemovePendingFolderForDevice(folder, device)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
removedPendingFolders = []map[string]string{
|
||||||
|
{
|
||||||
|
"folderID": folder,
|
||||||
|
"deviceID": device.String(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(removedPendingFolders) > 0 {
|
||||||
|
m.evLogger.Log(events.PendingFoldersChanged, map[string]interface{}{
|
||||||
|
"removed": removedPendingFolders,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// mapFolders returns a map of folder ID to folder configuration for the given
|
// mapFolders returns a map of folder ID to folder configuration for the given
|
||||||
// slice of folder configurations.
|
// slice of folder configurations.
|
||||||
func mapFolders(folders []config.FolderConfiguration) map[string]config.FolderConfiguration {
|
func mapFolders(folders []config.FolderConfiguration) map[string]config.FolderConfiguration {
|
||||||
|
|||||||
Reference in New Issue
Block a user