Import/Export final touches

This commit is contained in:
Michal Horejsek
2020-08-12 13:56:49 +02:00
parent 4f0af0fb02
commit 658ead9fb3
82 changed files with 451 additions and 450 deletions

View File

@ -47,6 +47,18 @@ func (f *FrontendQt) LoadStructureForExport(addressOrID string) {
return
}
// Export has only one option to set time limits--by global time range.
// In case user changes file or because of some bug global time is saved
// to all rules, let's clear it, because there is no way to show it in
// GUI and user would be confused and see it does not work at all.
for _, rule := range f.transfer.GetRules() {
isActive := rule.Active
f.transfer.SetRule(rule.SourceMailbox, rule.TargetMailboxes, 0, 0)
if !isActive {
f.transfer.UnsetRule(rule.SourceMailbox)
}
}
f.TransferRules.setTransfer(f.transfer)
}
@ -65,55 +77,4 @@ func (f *FrontendQt) StartExport(rootPath, login, fileType string, attachEncrypt
f.transfer.SetSkipEncryptedMessages(!attachEncryptedBody)
progress := f.transfer.Start()
f.setProgressManager(progress)
/*
TODO
f.Qml.SetProgress(0.0)
f.Qml.SetProgressDescription(backend.ProgressInit)
f.Qml.SetTotal(0)
settings := backend.ExportSettings{
FilePath: fpath,
Login: login,
AttachEncryptedBody: attachEncryptedBody,
DateBegin: 0,
DateEnd: 0,
Labels: make(map[string]string),
}
if fileType == "EML" {
settings.FileTypeID = backend.EMLFormat
} else if fileType == "MBOX" {
settings.FileTypeID = backend.MBOXFormat
} else {
log.Errorln("Wrong file format:", fileType)
return
}
username, _, err := backend.ExtractUsername(login)
if err != nil {
log.Error("qtfrontend: cannot retrieve username from alias: ", err)
return
}
settings.User, err = backend.ExtractCurrentUser(username)
if err != nil && !errors.IsCode(err, errors.ErrUnlockUser) {
return
}
for _, entity := range f.PMStructure.entities {
if entity.IsFolderSelected {
settings.Labels[entity.FolderName] = entity.FolderId
}
}
settings.DateBegin = f.PMStructure.GlobalOptions.FromDate
settings.DateEnd = f.PMStructure.GlobalOptions.ToDate
settings.PM = backend.NewProcessManager()
f.setHandlers(settings.PM)
log.Debugln("start export", settings.FilePath)
go backend.Export(f.panicHandler, settings)
*/
}

View File

@ -59,10 +59,6 @@ func getTargetHashes(mboxes []transfer.Mailbox) (targetFolderID, targetLabelIDs
return
}
func isSystemMailbox(mbox transfer.Mailbox) bool {
return pmapi.IsSystemLabel(mbox.ID)
}
func newFolderInfo(mbox transfer.Mailbox, rule *transfer.Rule) *FolderInfo {
targetFolderID, targetLabelIDs := getTargetHashes(rule.TargetMailboxes)
@ -77,7 +73,7 @@ func newFolderInfo(mbox transfer.Mailbox, rule *transfer.Rule) *FolderInfo {
}
entry.FolderType = FolderTypeSystem
if !isSystemMailbox(mbox) {
if !pmapi.IsSystemLabel(mbox.ID) {
if mbox.IsExclusive {
entry.FolderType = FolderTypeFolder
} else {
@ -112,7 +108,7 @@ func (s *FolderStructure) saveRule(info *FolderInfo) error {
return s.transfer.SetRule(sourceMbox, targetMboxes, info.FromDate, info.ToDate)
}
func (s *FolderInfo) updateTgtLblIDs(targetLabelsSet map[string]struct{}) {
func (s *FolderInfo) updateTargetLabelIDs(targetLabelsSet map[string]struct{}) {
targets := []string{}
for key := range targetLabelsSet {
targets = append(targets, key)
@ -120,17 +116,13 @@ func (s *FolderInfo) updateTgtLblIDs(targetLabelsSet map[string]struct{}) {
s.TargetLabelIDs = strings.Join(targets, ";")
}
func (s *FolderInfo) clearTgtLblIDs() {
s.TargetLabelIDs = ""
}
func (s *FolderInfo) AddTargetLabel(targetID string) {
if targetID == "" {
return
}
targetLabelsSet := s.getSetOfLabels()
targetLabelsSet[targetID] = struct{}{}
s.updateTgtLblIDs(targetLabelsSet)
s.updateTargetLabelIDs(targetLabelsSet)
}
func (s *FolderInfo) RemoveTargetLabel(targetID string) {
@ -139,7 +131,7 @@ func (s *FolderInfo) RemoveTargetLabel(targetID string) {
}
targetLabelsSet := s.getSetOfLabels()
delete(targetLabelsSet, targetID)
s.updateTgtLblIDs(targetLabelsSet)
s.updateTargetLabelIDs(targetLabelsSet)
}
func (s *FolderInfo) IsType(askType string) bool {
@ -387,7 +379,7 @@ func (s *FolderStructure) setTargetFolderID(id, target string) {
s.changedEntityRole(i, i, TargetFolderID)
if target == "" { // do not import
before := info.TargetLabelIDs
info.clearTgtLblIDs()
info.TargetLabelIDs = ""
if err := s.saveRule(info); err != nil {
info.TargetLabelIDs = before
log.WithError(err).WithField("id", id).WithField("target", target).Error("Cannot set target")

View File

@ -29,9 +29,9 @@ import (
qtcommon "github.com/ProtonMail/proton-bridge/internal/frontend/qt-common"
"github.com/ProtonMail/proton-bridge/internal/frontend/types"
"github.com/ProtonMail/proton-bridge/internal/transfer"
"github.com/ProtonMail/proton-bridge/internal/updates"
"github.com/ProtonMail/proton-bridge/pkg/config"
"github.com/ProtonMail/proton-bridge/pkg/listener"
"github.com/ProtonMail/proton-bridge/pkg/updates"
"github.com/therecipe/qt/core"
"github.com/therecipe/qt/gui"
@ -185,7 +185,7 @@ func (f *FrontendQt) qtSetupQmlAndStructures() {
f.View.Load(core.NewQUrl3("qrc:/uiie.qml", 0))
// TODO set the first start flag
log.Error("Get FirstStart: Not implemented")
//log.Error("Get FirstStart: Not implemented")
//if prefs.Get(prefs.FirstStart) == "true" {
if false {
f.Qml.SetIsFirstStart(true)
@ -226,7 +226,6 @@ func (f *FrontendQt) QtExecute(Procedure func(*FrontendQt) error) error {
return err
}
log.Debug("Closing...")
log.Error("Set FirstStart: Not implemented")
//prefs.Set(prefs.FirstStart, "false")
return nil
}
@ -318,27 +317,31 @@ func (f *FrontendQt) setProgressManager(progress *transfer.Progress) {
f.Qml.ConnectCancelProcess(func() {
progress.Stop()
})
f.Qml.SetProgress(0)
go func() {
log.Trace("Start reading updates")
defer func() {
log.Trace("Finishing reading updates")
f.Qml.DisconnectPauseProcess()
f.Qml.DisconnectResumeProcess()
f.Qml.DisconnectCancelProcess()
f.Qml.SetProgress(1)
f.progress = nil
f.ErrorList.Progress = nil
}()
//TODO get log file (in old code it was here, but this is ugly place probably somewhere else)
updates := progress.GetUpdateChannel()
for range updates {
if progress.IsStopped() {
break
}
failed, imported, _, _, total := progress.GetCounts()
if total != 0 { // udate total
if total != 0 {
f.Qml.SetTotal(int(total))
}
f.Qml.SetProgressFails(int(failed))
f.Qml.SetProgressDescription(progress.PauseReason()) // TODO add description when changing folders?
f.Qml.SetProgressDescription(progress.PauseReason())
if total > 0 {
newProgress := float32(imported+failed) / float32(total)
if newProgress >= 0 && newProgress != f.Qml.Progress() {
@ -436,7 +439,7 @@ func (f *FrontendQt) getLocalVersionInfo() {
// LeastUsedColor is intended to return color for creating a new inbox or label.
func (f *FrontendQt) leastUsedColor() string {
if f.transfer == nil {
log.Errorln("Getting least used color before transfer exist.")
log.Warnln("Getting least used color before transfer exist.")
return "#7272a7"
}

View File

@ -74,6 +74,8 @@ func (f *FrontendQt) loadStructuresForImport() error {
}
func (f *FrontendQt) StartImport(email string) { // TODO email not needed
log.Trace("Starting import")
f.Qml.SetProgressDescription("init") // TODO use const
f.Qml.SetProgressFails(0)
f.Qml.SetProgress(0.0)

View File

@ -55,8 +55,8 @@ func newMboxList(t *TransferRules, rule *transfer.Rule, containsFolders bool) *M
m.log = log.
WithField("rule", m.rule.SourceMailbox.Hash()).
WithField("folders", m.containsFolders)
m.updateSelectedIndex()
m.EndResetModel()
m.itemsChanged(rule)
return m
}
@ -71,11 +71,6 @@ func (m *MboxList) rowCount(index *core.QModelIndex) int {
}
func (m *MboxList) roleNames() map[int]*core.QByteArray {
m.log.
WithField("isActive", MboxIsActive).
WithField("id", MboxID).
WithField("color", MboxColor).
Debug("role names")
return map[int]*core.QByteArray{
MboxIsActive: qtcommon.NewQByteArrayFromString("isActive"),
MboxID: qtcommon.NewQByteArrayFromString("mboxID"),
@ -88,17 +83,17 @@ func (m *MboxList) roleNames() map[int]*core.QByteArray {
func (m *MboxList) data(index *core.QModelIndex, role int) *core.QVariant {
allTargets := m.targetMailboxes()
i, valid := index.Row(), index.IsValid()
l := m.log.WithField("row", i).WithField("role", role)
l.Trace("called data()")
i := index.Row()
log := m.log.WithField("row", i).WithField("role", role)
log.Trace("Mbox data")
if !valid || i >= len(allTargets) {
l.WithField("row", i).Warning("Invalid index")
if i >= len(allTargets) {
log.Warning("Invalid index")
return core.NewQVariant()
}
if m.transfer == nil {
l.Warning("Requested mbox list data before transfer is connected")
log.Warning("Requested mbox list data before transfer is connected")
return qtcommon.NewQVariantString("")
}
@ -131,7 +126,7 @@ func (m *MboxList) data(index *core.QModelIndex, role int) *core.QVariant {
return qtcommon.NewQVariantString(mbox.Color)
default:
l.Error("Requested mbox list data with unknown role")
log.Error("Requested mbox list data with unknown role")
return qtcommon.NewQVariantString("")
}
}
@ -161,11 +156,10 @@ func (m *MboxList) filter(mailboxes []transfer.Mailbox) (filtered []transfer.Mai
func (m *MboxList) itemsChanged(rule *transfer.Rule) {
m.rule = rule
allTargets := m.targetMailboxes()
l := m.log.WithField("count", len(allTargets))
l.Trace("called itemChanged()")
defer func() {
l.WithField("selected", m.SelectedIndex()).Trace("index updated")
}()
m.log.WithField("count", len(allTargets)).Trace("Mbox items changed")
m.updateSelectedIndex()
// NOTE: Be careful with indices: If they are invalid the DataChanged
// signal will not be sent to QML e.g. `end == rowCount - 1`
@ -175,7 +169,10 @@ func (m *MboxList) itemsChanged(rule *transfer.Rule) {
changedRoles := []int{MboxIsActive}
m.DataChanged(begin, end, changedRoles)
}
}
func (m *MboxList) updateSelectedIndex() {
allTargets := m.targetMailboxes()
for index, targetMailbox := range allTargets {
for _, selectedTarget := range m.rule.TargetMailboxes {
if targetMailbox.Hash() == selectedTarget.Hash() {

View File

@ -0,0 +1,83 @@
// Copyright (c) 2020 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge 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 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge 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.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
// +build !nogui
package qtie
import (
"io/ioutil"
"os"
"path/filepath"
)
// PathStatus maps folder properties to flag
type PathStatus int
// Definition of PathStatus flags
const (
PathOK PathStatus = 1 << iota
PathEmptyPath
PathWrongPath
PathNotADir
PathWrongPermissions
PathDirEmpty
)
// CheckPathStatus return PathStatus flag as int
func CheckPathStatus(path string) int {
stat := PathStatus(0)
// path is not empty
if path == "" {
stat |= PathEmptyPath
return int(stat)
}
// is dir
fi, err := os.Lstat(path)
if err != nil {
stat |= PathWrongPath
return int(stat)
}
if fi.IsDir() {
// can open
files, err := ioutil.ReadDir(path)
if err != nil {
stat |= PathWrongPermissions
return int(stat)
}
// empty folder
if len(files) == 0 {
stat |= PathDirEmpty
}
// can write
tmpFile := filepath.Join(path, "tmp")
for err == nil {
tmpFile += "tmp"
_, err = os.Lstat(tmpFile)
}
err = os.Mkdir(tmpFile, 0750)
if err != nil {
stat |= PathWrongPermissions
return int(stat)
}
_ = os.Remove(tmpFile)
} else {
stat |= PathNotADir
}
stat |= PathOK
return int(stat)
}

View File

@ -44,6 +44,7 @@ type TransferRules struct {
_ func(sourceID string, targetID string) `slot:"addTargetID,auto"`
_ func(sourceID string, targetID string) `slot:"removeTargetID,auto"`
// globalFromDate and globalToDate is just default value for GUI, always zero.
_ int `property:"globalFromDate"`
_ int `property:"globalToDate"`
_ bool `property:"isLabelGroupSelected"`
@ -90,21 +91,23 @@ func (t *TransferRules) roleNames() map[int]*core.QByteArray {
}
func (t *TransferRules) data(index *core.QModelIndex, role int) *core.QVariant {
i, valid := index.Row(), index.IsValid()
if !valid || i >= t.rowCount(index) {
log.WithField("row", i).Warning("Invalid index")
return core.NewQVariant()
}
i := index.Row()
allRules := t.transfer.GetRules()
log := log.WithField("row", i).WithField("role", role)
log.Trace("Transfer rules data")
if i >= len(allRules) {
log.Warning("Invalid index")
return core.NewQVariant()
}
if t.transfer == nil {
log.Warning("Requested transfer rules data before transfer is connected")
return qtcommon.NewQVariantString("")
}
rule := t.transfer.GetRules()[i]
rule := allRules[i]
switch role {
case MboxIsActive:
@ -160,6 +163,9 @@ func (t *TransferRules) setTransfer(transfer *transfer.Transfer) {
t.transfer = transfer
t.targetFoldersCache = make(map[string]*MboxList)
t.targetLabelsCache = make(map[string]*MboxList)
t.updateGroupSelection()
}
@ -196,7 +202,9 @@ func (t *TransferRules) targetLabels(sourceID string) *MboxList {
// Setters
func (t *TransferRules) setIsGroupActive(groupName string, isActive bool) {
wantExclusive := (groupName == FolderTypeLabel)
log.WithField("group", groupName).WithField("active", isActive).Trace("Setting group as active/inactive")
wantExclusive := (groupName == FolderTypeFolder)
for _, rule := range t.transfer.GetRules() {
if rule.SourceMailbox.IsExclusive != wantExclusive {
continue
@ -265,6 +273,7 @@ func (t *TransferRules) addTargetID(sourceID string, targetID string) {
newTargetMailboxes = append(newTargetMailboxes, *targetMailboxToAdd)
}
t.setRule(rule.SourceMailbox, newTargetMailboxes, rule.FromTime, rule.ToTime, []int{RuleTargetLabelColors})
t.updateTargetSelection(sourceID, targetMailboxToAdd.IsExclusive)
}
func (t *TransferRules) removeTargetID(sourceID string, targetID string) {
@ -286,10 +295,14 @@ func (t *TransferRules) removeTargetID(sourceID string, targetID string) {
}
}
t.setRule(rule.SourceMailbox, newTargetMailboxes, rule.FromTime, rule.ToTime, []int{RuleTargetLabelColors})
t.updateTargetSelection(sourceID, targetMailboxToRemove.IsExclusive)
}
// Helpers
// getRule returns rule for given source ID.
// WARN: Always get new rule after change because previous pointer points to
// outdated struct with old data.
func (t *TransferRules) getRule(sourceID string) *transfer.Rule {
mailbox := t.getMailbox(t.transfer.SourceMailboxes, sourceID)
if mailbox == nil {
@ -331,20 +344,19 @@ func (t *TransferRules) unsetRule(sourceMailbox transfer.Mailbox) {
}
func (t *TransferRules) ruleChanged(sourceMailbox transfer.Mailbox, changedRoles []int) {
for row, rule := range t.transfer.GetRules() {
allRules := t.transfer.GetRules()
for row, rule := range allRules {
if rule.SourceMailbox.Hash() != sourceMailbox.Hash() {
continue
}
t.targetFolders(sourceMailbox.Hash()).itemsChanged(rule)
t.targetLabels(sourceMailbox.Hash()).itemsChanged(rule)
index := t.Index(row, 0, core.NewQModelIndex())
if !index.IsValid() || row >= t.rowCount(index) {
if !index.IsValid() || row >= len(allRules) {
log.WithField("row", row).Warning("Invalid index")
return
}
log.WithField("row", row).Trace("Transfer rule changed")
t.DataChanged(index, index, changedRoles)
break
}
@ -375,3 +387,16 @@ func (t *TransferRules) updateGroupSelection() {
t.SetIsLabelGroupSelected(areAllLabelsSelected)
t.SetIsFolderGroupSelected(areAllFoldersSelected)
}
func (t *TransferRules) updateTargetSelection(sourceID string, updateFolderSelect bool) {
rule := t.getRule(sourceID)
if rule == nil {
return
}
if updateFolderSelect {
t.targetFolders(rule.SourceMailbox.Hash()).itemsChanged(rule)
} else {
t.targetLabels(rule.SourceMailbox.Hash()).itemsChanged(rule)
}
}

View File

@ -22,7 +22,6 @@ package qtie
import (
"runtime"
qtcommon "github.com/ProtonMail/proton-bridge/internal/frontend/qt-common"
"github.com/therecipe/qt/core"
)
@ -181,7 +180,7 @@ func (s *GoQMLInterface) SetFrontend(f *FrontendQt) {
s.ConnectStartExport(f.StartExport)
s.ConnectStartImport(f.StartImport)
s.ConnectCheckPathStatus(qtcommon.CheckPathStatus)
s.ConnectCheckPathStatus(CheckPathStatus)
s.ConnectStartUpdate(f.StartUpdate)