app/core/CalendarOutboxRefused.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // F108-12 (Sprint 108 user review): writes the server refuses. Nextcloud | ||
| 2 | // answers 404 to a PUT it refuses in a calendar shared with the user while | ||
| 3 | // a GET still returns the item; that is confirmed before it counts as | ||
| 4 | // "deleted on the server" (a conflict), and an item the server still has is | ||
| 5 | // a refused write: bounded retries, then "failed" — with the user's ways out | ||
| 6 | // (try again now, or drop the local change for the server's version). | ||
| 7 | #include "CalendarOutbox.h" | ||
| 8 | |||
| 9 | #include "data/CalendarStore.h" | ||
| 10 | #include "service/CalDavClient.h" | ||
| 11 | |||
| 12 | #include <QLoggingCategory> | ||
| 13 | |||
| 14 | Q_DECLARE_LOGGING_CATEGORY(lcCalendarOutbox) | ||
| 15 | |||
| 16 | 8 | void CalendarOutbox::confirmDeletedOnServer(const CalendarOutboxEntry &entry, const QString &url, | |
| 17 | const Endpoint &endpoint) { | ||
| 18 | 8 | CalDavClient *client = clientFor(endpoint); | |
| 19 | 8 | const quint64 request = client->getResource(url); | |
| 20 |
1/1✓ Branch 5 → 6 taken 8 times.
|
8 | connect(client, &CalDavClient::resourceResponse, this, [this, request, entry](const DavResponse &response) { |
| 21 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 8 times.
|
8 | if (response.request != request) |
| 22 | ✗ | return; | |
| 23 |
3/4✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 6 taken 6 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 21 taken 2 times.
|
8 | if (response.status == 404 || response.status == 410) { |
| 24 |
3/5✓ Branch 12 → 13 taken 6 times.
✓ Branch 17 → 18 taken 6 times.
✓ Branch 17 → 19 taken 6 times.
✗ Branch 63 → 64 not taken.
✗ Branch 63 → 65 not taken.
|
12 | markConflict(entry, QString(), QString(), {QStringLiteral("deleted")}); |
| 25 | 6 | return; | |
| 26 | } | ||
| 27 |
1/2✓ Branch 21 → 22 taken 2 times.
✗ Branch 21 → 38 not taken.
|
2 | if (response.status == 200) { |
| 28 | // The server still has it: not a deletion to ask about, but a write | ||
| 29 | // it refuses here — bounded retries, then the visible "failed" state. | ||
| 30 |
7/7✓ Branch 22 → 23 taken 2 times.
✓ Branch 26 → 27 taken 2 times.
✓ Branch 27 → 28 taken 2 times.
✓ Branch 28 → 29 taken 2 times.
✓ Branch 29 → 30 taken 2 times.
✓ Branch 33 → 24 taken 2 times.
✓ Branch 33 → 34 taken 2 times.
|
4 | qCWarning(lcCalendarOutbox) << "The server refuses writing" << entry.uid << "(404 on PUT, 200 on GET)"; |
| 31 |
2/2✓ Branch 34 → 35 taken 2 times.
✓ Branch 35 → 36 taken 2 times.
|
2 | retryLater(entry, tr("The server refuses changes to this item here (it still has it)."), true); |
| 32 | 2 | return; | |
| 33 | } | ||
| 34 | // Neither answer (the network, a server error): try the write again later. | ||
| 35 | ✗ | retryLater(entry, response.error.isEmpty() ? QStringLiteral("HTTP %1").arg(response.status) : response.error, false); | |
| 36 |
1/5✓ Branch 9 → 10 taken 6 times.
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 73 not taken.
✗ Branch 71 → 72 not taken.
✗ Branch 71 → 73 not taken.
|
12 | }); |
| 37 | 8 | } | |
| 38 | |||
| 39 | 1 | bool CalendarOutbox::retryWrite(const QString &uid, const QString &accountId, const QString &calendarPath) { | |
| 40 | 1 | CalendarStore *store = m_deps.store; | |
| 41 |
1/1✓ Branch 2 → 3 taken 1 time.
|
1 | auto entry = store->outboxEntry(accountId, calendarPath, uid); |
| 42 |
3/6✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 9 not taken.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 1 time.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 1 time.
|
1 | if (!entry || entry->state == QLatin1String("conflict")) |
| 43 | ✗ | return false; | |
| 44 | 1 | entry->state = QStringLiteral("pending"); | |
| 45 | 1 | entry->attempts = 0; | |
| 46 | 1 | entry->nextAttempt = 0; | |
| 47 |
1/1✓ Branch 23 → 24 taken 1 time.
|
1 | store->updateOutbox(*entry); |
| 48 |
7/7✓ Branch 24 → 25 taken 1 time.
✓ Branch 28 → 29 taken 1 time.
✓ Branch 29 → 30 taken 1 time.
✓ Branch 30 → 31 taken 1 time.
✓ Branch 31 → 32 taken 1 time.
✓ Branch 35 → 26 taken 1 time.
✓ Branch 35 → 36 taken 1 time.
|
2 | qCInfo(lcCalendarOutbox) << "Retrying the write of" << uid << "now"; |
| 49 |
1/1✓ Branch 36 → 37 taken 1 time.
|
1 | publishChange(); |
| 50 |
1/1✓ Branch 37 → 38 taken 1 time.
|
1 | requestFlush(); |
| 51 | 1 | return true; | |
| 52 | 1 | } | |
| 53 | |||
| 54 | 1 | bool CalendarOutbox::discardLocalChange(const QString &uid, const QString &accountId, const QString &calendarPath) { | |
| 55 | 1 | CalendarStore *store = m_deps.store; | |
| 56 |
1/1✓ Branch 2 → 3 taken 1 time.
|
1 | const auto entry = store->outboxEntry(accountId, calendarPath, uid); |
| 57 |
6/13✓ Branch 4 → 5 taken 1 time.
✗ Branch 4 → 12 not taken.
✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 12 not taken.
✓ Branch 9 → 10 taken 1 time.
✗ Branch 11 → 12 not taken.
✓ Branch 11 → 13 taken 1 time.
✓ Branch 14 → 15 taken 1 time.
✗ Branch 14 → 16 not taken.
✗ Branch 16 → 17 not taken.
✓ Branch 16 → 18 taken 1 time.
✗ Branch 60 → 61 not taken.
✗ Branch 60 → 62 not taken.
|
1 | if (!entry || entry->state == QLatin1String("conflict") || m_inFlight.contains(key(accountId, calendarPath, uid))) |
| 58 | ✗ | return false; | |
| 59 |
4/7✓ Branch 19 → 20 taken 1 time.
✗ Branch 19 → 23 not taken.
✓ Branch 20 → 21 taken 1 time.
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 1 time.
✗ Branch 24 → 25 not taken.
✓ Branch 24 → 26 taken 1 time.
|
1 | if (m_deps.networkAllowed && !m_deps.networkAllowed()) |
| 60 | ✗ | return false; | |
| 61 |
1/1✓ Branch 26 → 27 taken 1 time.
|
1 | const auto endpoint = m_deps.endpoint(accountId); |
| 62 |
1/2✗ Branch 28 → 29 not taken.
✓ Branch 28 → 30 taken 1 time.
|
1 | if (!endpoint) |
| 63 | ✗ | return false; | |
| 64 |
1/1✓ Branch 31 → 32 taken 1 time.
|
1 | CalDavClient *client = clientFor(*endpoint); |
| 65 |
1/1✓ Branch 33 → 34 taken 1 time.
|
1 | const QString url = client->eventResourceUrl(entry->href, calendarPath, uid); |
| 66 |
2/2✓ Branch 34 → 35 taken 1 time.
✓ Branch 35 → 36 taken 1 time.
|
1 | m_inFlight.insert(key(accountId, calendarPath, uid)); |
| 67 |
1/1✓ Branch 37 → 38 taken 1 time.
|
1 | const quint64 request = client->getResource(url); |
| 68 |
7/7✓ Branch 38 → 39 taken 1 time.
✓ Branch 42 → 43 taken 1 time.
✓ Branch 43 → 44 taken 1 time.
✓ Branch 44 → 45 taken 1 time.
✓ Branch 45 → 46 taken 1 time.
✓ Branch 49 → 40 taken 1 time.
✓ Branch 49 → 50 taken 1 time.
|
2 | qCInfo(lcCalendarOutbox) << "Discarding the local change of" << uid << "- fetching the server version"; |
| 69 |
1/1✓ Branch 52 → 53 taken 1 time.
|
1 | connect(client, &CalDavClient::resourceResponse, this, [this, request, entry = *entry](const DavResponse &response) { |
| 70 |
1/2✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1 time.
|
1 | if (response.request != request) |
| 71 | 1 | return; | |
| 72 | 1 | CalendarStore *store = m_deps.store; | |
| 73 |
1/1✓ Branch 4 → 5 taken 1 time.
|
1 | finishInFlight(entry); |
| 74 |
2/2✓ Branch 5 → 6 taken 1 time.
✓ Branch 6 → 7 taken 1 time.
|
1 | const QString local = QString::fromUtf8(localBody(entry)); |
| 75 |
1/2✓ Branch 8 → 9 taken 1 time.
✗ Branch 8 → 23 not taken.
|
1 | if (response.status == 200) { |
| 76 |
1/1✓ Branch 12 → 13 taken 1 time.
|
2 | recordHistory(entry, QStringLiteral("server"), local); |
| 77 |
3/4✓ Branch 15 → 16 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
✓ Branch 18 → 19 taken 1 time.
✗ Branch 18 → 41 not taken.
|
1 | if (adoptServerVersion(entry, QString::fromUtf8(response.body), response.etag)) { |
| 78 |
2/2✓ Branch 19 → 20 taken 1 time.
✓ Branch 20 → 21 taken 1 time.
|
1 | emit statusMessage(tr("Your change was dropped; the server's version is back.")); |
| 79 | 1 | return; | |
| 80 | } | ||
| 81 | ✗ | } else if (response.status == 404 || response.status == 410) { | |
| 82 | ✗ | recordHistory(entry, QStringLiteral("server"), local); | |
| 83 | ✗ | if (adoptServerVersion(entry, QString(), QString())) { | |
| 84 | ✗ | emit statusMessage(tr("Your change was dropped; the server no longer has this item.")); | |
| 85 | ✗ | return; | |
| 86 | } | ||
| 87 | } | ||
| 88 | ✗ | qCWarning(lcCalendarOutbox) << "Could not drop the local change of" << entry.uid << "status" << response.status; | |
| 89 | ✗ | store->updateOutbox(entry); | |
| 90 | ✗ | emit statusMessage(tr("The server's version could not be fetched. Try again later.")); | |
| 91 |
1/2✗ Branch 60 → 61 not taken.
✓ Branch 60 → 63 taken 1 time.
|
1 | }); |
| 92 | 1 | return true; | |
| 93 | 1 | } | |
| 94 |