• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IJHack / QtPass / 23687659448

28 Mar 2026 02:51PM UTC coverage: 18.401% (-0.003%) from 18.404%
23687659448

Pull #822

github

web-flow
Merge 2b3ee08c2 into 94bbe817e
Pull Request #822: Potential fixes for 3 code quality findings

0 of 2 new or added lines in 1 file covered. (0.0%)

28 existing lines in 1 file now uncovered.

925 of 5027 relevant lines covered (18.4%)

7.53 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/usersdialog.cpp
1
// SPDX-FileCopyrightText: 2016 Anne Jan Brouwer
2
// SPDX-License-Identifier: GPL-3.0-or-later
3
#include "usersdialog.h"
4
#include "qtpasssettings.h"
5
#include "ui_usersdialog.h"
6
#include <QCloseEvent>
7
#include <QKeyEvent>
8
#include <QMessageBox>
9
#include <QRegularExpression>
10
#include <QSet>
11
#include <QWidget>
12
#include <utility>
13

14
#ifdef QT_DEBUG
15
#include "debughelper.h"
16
#endif
17
/**
18
 * @brief UsersDialog::UsersDialog basic constructor
19
 * @param parent
20
 */
21
UsersDialog::UsersDialog(QString dir, QWidget *parent)
×
22
    : QDialog(parent), ui(new Ui::UsersDialog), m_dir(std::move(dir)) {
×
23

24
  ui->setupUi(this);
×
25

26
  QList<UserInfo> users = QtPassSettings::getPass()->listKeys();
×
27
  if (users.isEmpty()) {
×
28
    QMessageBox::critical(parent, tr("Keylist missing"),
×
29
                          tr("Could not fetch list of available GPG keys"));
×
NEW
30
    reject();
×
31
  }
32

33
  QList<UserInfo> secret_keys = QtPassSettings::getPass()->listKeys("", true);
×
34
  QSet<QString> secretKeyIds;
35
  for (const UserInfo &sec : secret_keys) {
×
36
    secretKeyIds.insert(sec.key_id);
×
37
  }
38
  for (auto &user : users) {
×
39
    if (secretKeyIds.contains(user.key_id)) {
×
40
      user.have_secret = true;
×
41
    }
42
  }
43

44
  QList<UserInfo> selected_users;
×
45
  int count = 0;
×
46

47
  QStringList recipients = QtPassSettings::getPass()->getRecipientString(
×
48
      m_dir.isEmpty() ? "" : m_dir, " ", &count);
×
49
  if (!recipients.isEmpty()) {
×
50
    selected_users = QtPassSettings::getPass()->listKeys(recipients);
×
51
  }
52
  QSet<QString> selectedKeyIds;
53
  for (const UserInfo &sel : selected_users) {
×
54
    selectedKeyIds.insert(sel.key_id);
×
55
  }
56
  for (auto &user : users) {
×
57
    if (selectedKeyIds.contains(user.key_id)) {
×
58
      user.enabled = true;
×
59
    }
60
  }
61

62
  if (count > selected_users.size()) {
×
63
    // Some keys seem missing from keyring, add them separately
64
    QStringList allRecipients = QtPassSettings::getPass()->getRecipientList(
×
65
        m_dir.isEmpty() ? "" : m_dir);
×
66
    for (const QString &recipient : allRecipients) {
×
67
      if (QtPassSettings::getPass()->listKeys(recipient).empty()) {
×
68
        UserInfo i;
×
69
        i.enabled = true;
×
70
        i.key_id = recipient;
×
71
        i.name = " ?? " + tr("Key not found in keyring");
×
72
        users.append(i);
73
      }
×
74
    }
75
  }
76

77
  m_userList = users;
78
  populateList();
×
79

80
  connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
×
81
          &UsersDialog::accept);
×
82
  connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
×
83
  connect(ui->listWidget, &QListWidget::itemChanged, this,
×
84
          &UsersDialog::itemChange);
×
85

86
  ui->lineEdit->setClearButtonEnabled(true);
×
87
}
×
88

89
/**
90
 * @brief UsersDialog::~UsersDialog basic destructor.
91
 */
92
UsersDialog::~UsersDialog() { delete ui; }
×
93

94
Q_DECLARE_METATYPE(UserInfo *)
×
95

96
/**
97
 * @brief UsersDialog::accept
98
 */
UNCOV
99
void UsersDialog::accept() {
×
100
  QtPassSettings::getPass()->Init(m_dir, m_userList);
×
101

UNCOV
102
  QDialog::accept();
×
103
}
×
104

105
/**
106
 * @brief UsersDialog::closeEvent might have to store size and location if that
107
 * is wanted.
108
 * @param event
109
 */
UNCOV
110
void UsersDialog::closeEvent(QCloseEvent *event) {
×
111
  // TODO(annejan): save window size or something
112
  event->accept();
UNCOV
113
}
×
114

115
/**
116
 * @brief UsersDialog::keyPressEvent clear the lineEdit when escape is pressed.
117
 * No action for Enter currently.
118
 * @param event
119
 */
UNCOV
120
void UsersDialog::keyPressEvent(QKeyEvent *event) {
×
121
  switch (event->key()) {
×
122
  case Qt::Key_Escape:
×
123
    ui->lineEdit->clear();
×
124
    break;
×
125
  default:
126
    break;
127
  }
UNCOV
128
}
×
129

130
/**
131
 * @brief UsersDialog::itemChange update the item information.
132
 * @param item
133
 */
UNCOV
134
void UsersDialog::itemChange(QListWidgetItem *item) {
×
135
  if (!item) {
×
136
    return;
137
  }
UNCOV
138
  auto *info = item->data(Qt::UserRole).value<UserInfo *>();
×
139
  if (!info) {
×
140
    return;
141
  }
UNCOV
142
  info->enabled = item->checkState() == Qt::Checked;
×
143
}
144

145
/**
146
 * @brief UsersDialog::populateList update the view based on filter options
147
 * (such as searching).
148
 * @param filter
149
 */
UNCOV
150
void UsersDialog::populateList(const QString &filter) {
×
151
  QRegularExpression nameFilter(
UNCOV
152
      QRegularExpression::wildcardToRegularExpression("*" + filter + "*"),
×
153
      QRegularExpression::CaseInsensitiveOption);
×
154
  ui->listWidget->clear();
×
155

UNCOV
156
  for (const auto &user : m_userList) {
×
NEW
157
    if (!passesFilter(user, filter, nameFilter)) {
×
158
      continue;
×
159
    }
160

UNCOV
161
    auto *item = new QListWidgetItem(buildUserText(user), ui->listWidget);
×
162
    applyUserStyling(item, user);
×
163
    item->setCheckState(user.enabled ? Qt::Checked : Qt::Unchecked);
×
164
    item->setData(Qt::UserRole, QVariant::fromValue(&user));
×
165
    ui->listWidget->addItem(item);
×
166
  }
UNCOV
167
}
×
168

UNCOV
169
bool UsersDialog::passesFilter(const UserInfo &user, const QString &filter,
×
170
                               const QRegularExpression &nameFilter) const {
UNCOV
171
  if (!filter.isEmpty() && !nameFilter.match(user.name).hasMatch()) {
×
172
    return false;
173
  }
UNCOV
174
  if (!user.isValid() && !ui->checkBox->isChecked()) {
×
175
    return false;
176
  }
UNCOV
177
  const bool expired = isUserExpired(user);
×
178
  return !(expired && !ui->checkBox->isChecked());
×
179
}
180

UNCOV
181
bool UsersDialog::isUserExpired(const UserInfo &user) const {
×
182
  return user.expiry.toSecsSinceEpoch() > 0 &&
×
183
         QDateTime::currentDateTime() > user.expiry;
×
184
}
185

UNCOV
186
QString UsersDialog::buildUserText(const UserInfo &user) const {
×
187
  QString text = user.name + "\n" + user.key_id;
×
188
  if (user.created.toSecsSinceEpoch() > 0) {
×
189
    text += " " + tr("created") + " " +
×
190
            QLocale::system().toString(user.created, QLocale::ShortFormat);
×
191
  }
UNCOV
192
  if (user.expiry.toSecsSinceEpoch() > 0) {
×
193
    text += " " + tr("expires") + " " +
×
194
            QLocale::system().toString(user.expiry, QLocale::ShortFormat);
×
195
  }
UNCOV
196
  return text;
×
197
}
198

UNCOV
199
void UsersDialog::applyUserStyling(QListWidgetItem *item,
×
200
                                   const UserInfo &user) const {
UNCOV
201
  if (user.have_secret) {
×
202
    item->setForeground(Qt::blue);
×
203
    QFont font = item->font();
×
204
    font.setBold(true);
UNCOV
205
    item->setFont(font);
×
206
  } else if (!user.isValid()) {
×
207
    item->setBackground(Qt::darkRed);
×
208
    item->setForeground(Qt::white);
×
209
  } else if (isUserExpired(user)) {
×
210
    item->setForeground(Qt::darkRed);
×
211
  } else if (!user.fullyValid()) {
×
212
    item->setBackground(Qt::darkYellow);
×
213
    item->setForeground(Qt::white);
×
214
  }
UNCOV
215
}
×
216

217
/**
218
 * @brief UsersDialog::on_lineEdit_textChanged typing in the searchbox.
219
 * @param filter
220
 */
UNCOV
221
void UsersDialog::on_lineEdit_textChanged(const QString &filter) {
×
222
  populateList(filter);
×
223
}
×
224

225
/**
226
 * @brief UsersDialog::on_checkBox_clicked filtering.
227
 */
UNCOV
228
void UsersDialog::on_checkBox_clicked() { populateList(ui->lineEdit->text()); }
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc