From 9a0e39d16c88f03cce6f3d6ec2c8d0fd07504a82 Mon Sep 17 00:00:00 2001 From: Martin Burchell Date: Tue, 16 Apr 2024 15:04:46 +0100 Subject: [PATCH 1/7] Don't go round in circles if the databases can't be deleted --- tablet_qt/core/camcopsapp.cpp | 56 ++++++++++++++++++++++++++++++----- tablet_qt/core/camcopsapp.h | 7 +++-- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/tablet_qt/core/camcopsapp.cpp b/tablet_qt/core/camcopsapp.cpp index cb078ecaa..578f94e3c 100644 --- a/tablet_qt/core/camcopsapp.cpp +++ b/tablet_qt/core/camcopsapp.cpp @@ -1336,7 +1336,19 @@ bool CamcopsApp::connectDatabaseEncryption(QString& new_user_password, if (!userConfirmedRetryPassword()) { if (userConfirmedDeleteDatabases()) { qInfo() << "... deleting databases."; - deleteDatabases(); + QString error_string; + const bool ok = deleteDatabases(error_string); + if (!ok) + { + uifunc::alert( + tr("CamCOPS could not delete its databases:\n\n" + "%1\n" + "Please try to delete these files manually and restart CamCOPS\n" + ).arg(error_string)); + + user_cancelled_please_quit = true; + return false; + } qInfo() << "... recreating databases."; openOrCreateDatabases(); } @@ -1390,16 +1402,44 @@ bool CamcopsApp::userConfirmedDeleteDatabases() const } -void CamcopsApp::deleteDatabases() +bool CamcopsApp::deleteDatabases(QString& error_string) { - const QString data_filename = dbFullPath(dbfunc::DATA_DATABASE_FILENAME); - const QString sys_filename = dbFullPath(dbfunc::SYSTEM_DATABASE_FILENAME); + QString data_error_string; + QString sys_error_string; + + const bool data_ok = deleteDatabase(dbfunc::DATA_DATABASE_FILENAME, + data_error_string); + const bool sys_ok = deleteDatabase(dbfunc::SYSTEM_DATABASE_FILENAME, + sys_error_string); + + if (!data_ok) { + error_string = data_error_string; + } + + if (!sys_ok) { + error_string += "\n" + sys_error_string; + } - QFile data_file(data_filename); - data_file.remove(); + return data_ok && sys_ok; +} + + +bool CamcopsApp::deleteDatabase(const QString& filename, QString& error_string) +{ + const QString fullpath = dbFullPath(filename); + QFile file(fullpath); + const bool ok = file.remove(); + + if (!ok) { + error_string = tr( + "Failed to delete file:\n" + "%1\n" + "because of this error:\n" + "%2\n" + ).arg(fullpath, file.errorString()); + } - QFile sys_file(sys_filename); - sys_file.remove(); + return ok; } diff --git a/tablet_qt/core/camcopsapp.h b/tablet_qt/core/camcopsapp.h index dbbb5ec73..66bed2192 100644 --- a/tablet_qt/core/camcopsapp.h +++ b/tablet_qt/core/camcopsapp.h @@ -169,8 +169,11 @@ class CamcopsApp : public QApplication // Open our pair of databases, or create them if they don't exist. void openOrCreateDatabases(); - // Delete databases - void deleteDatabases(); + // Delete databases, returning true if successful + bool deleteDatabases(QString& error_string); + + // Delete the named database, returning true if successful + bool deleteDatabase(const QString& filename, QString& error_string); // Close our databases. void closeDatabases(); From 6df015861fe32c7394c7360426700552a22cf6e8 Mon Sep 17 00:00:00 2001 From: Martin Burchell Date: Tue, 16 Apr 2024 16:10:23 +0100 Subject: [PATCH 2/7] Delete the databases if initial password setup is cancelled Aborting the initial password entry dialog was leaving the databases in a state where a subsequent attempt to set the password would fail. --- tablet_qt/core/camcopsapp.cpp | 32 ++++++++++++++++++++++---------- tablet_qt/core/camcopsapp.h | 2 +- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/tablet_qt/core/camcopsapp.cpp b/tablet_qt/core/camcopsapp.cpp index 578f94e3c..dc0667f5f 100644 --- a/tablet_qt/core/camcopsapp.cpp +++ b/tablet_qt/core/camcopsapp.cpp @@ -1279,7 +1279,15 @@ bool CamcopsApp::connectDatabaseEncryption(QString& new_user_password, new_pw_text, new_pw_title, false /* require_old_password */, dummy_old_password, new_user_password, nullptr)) { + + // The user quit without setting a password. + // If we don't delete the database here, the next attempt to + // set up a password will fail (canReadDatabase() calls below + // will return false) and the user will be forced to set up + // another one. + deleteDatabases(); user_cancelled_please_quit = true; + return false; } qInfo() << "Encrypting databases for the first time..."; @@ -1336,16 +1344,9 @@ bool CamcopsApp::connectDatabaseEncryption(QString& new_user_password, if (!userConfirmedRetryPassword()) { if (userConfirmedDeleteDatabases()) { qInfo() << "... deleting databases."; - QString error_string; - const bool ok = deleteDatabases(error_string); + const bool ok = deleteDatabases(); if (!ok) { - uifunc::alert( - tr("CamCOPS could not delete its databases:\n\n" - "%1\n" - "Please try to delete these files manually and restart CamCOPS\n" - ).arg(error_string)); - user_cancelled_please_quit = true; return false; } @@ -1402,7 +1403,7 @@ bool CamcopsApp::userConfirmedDeleteDatabases() const } -bool CamcopsApp::deleteDatabases(QString& error_string) +bool CamcopsApp::deleteDatabases() { QString data_error_string; QString sys_error_string; @@ -1412,6 +1413,12 @@ bool CamcopsApp::deleteDatabases(QString& error_string) const bool sys_ok = deleteDatabase(dbfunc::SYSTEM_DATABASE_FILENAME, sys_error_string); + if (data_ok && sys_ok) { + return true; + } + + QString error_string; + if (!data_ok) { error_string = data_error_string; } @@ -1419,8 +1426,13 @@ bool CamcopsApp::deleteDatabases(QString& error_string) if (!sys_ok) { error_string += "\n" + sys_error_string; } + uifunc::alert( + tr("CamCOPS could not delete its databases:\n\n" + "%1\n" + "Please try to delete these files manually and restart CamCOPS\n" + ).arg(error_string)); - return data_ok && sys_ok; + return false; } diff --git a/tablet_qt/core/camcopsapp.h b/tablet_qt/core/camcopsapp.h index 66bed2192..3bdf8b15f 100644 --- a/tablet_qt/core/camcopsapp.h +++ b/tablet_qt/core/camcopsapp.h @@ -170,7 +170,7 @@ class CamcopsApp : public QApplication void openOrCreateDatabases(); // Delete databases, returning true if successful - bool deleteDatabases(QString& error_string); + bool deleteDatabases(); // Delete the named database, returning true if successful bool deleteDatabase(const QString& filename, QString& error_string); From 91e8bc33c850f677b18bfe727e1a72ac0031abf6 Mon Sep 17 00:00:00 2001 From: Martin Burchell Date: Tue, 16 Apr 2024 16:11:57 +0100 Subject: [PATCH 3/7] Bump Gunicorn to fix CVE-2024-1135 --- server/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/setup.py b/server/setup.py index 6297a4ae5..1211a6a30 100644 --- a/server/setup.py +++ b/server/setup.py @@ -87,7 +87,7 @@ # FHIR export, our fork until https://github.com/smart-on-fhir/client-py/pull/105 is merged # noqa "fhirclient @ git+https://github.com/ucam-department-of-psychiatry/client-py@128bbe3c2194a51ba6ff8cf880ef2fdb9bfcc2d6#egg=fhirclient-4.0.0.1", # noqa: E501 "flower==1.2.0", # monitor for Celery - "gunicorn==20.1.0", # web server (Unix only) + "gunicorn==21.2.0", # web server (Unix only) "hl7==0.3.5", # For HL7 export # Celery dependency for Python <= 3.7; workaround import error # https://github.com/celery/celery/issues/7783; scheduled to be fixed in From d038fc11687044af2166a06e64dd4a76b56298d4 Mon Sep 17 00:00:00 2001 From: Martin Burchell Date: Tue, 16 Apr 2024 16:16:46 +0100 Subject: [PATCH 4/7] Update changelog --- docs/source/changelog.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst index 91bf4f9b1..c6277f2d8 100644 --- a/docs/source/changelog.rst +++ b/docs/source/changelog.rst @@ -3895,3 +3895,8 @@ Current C++/SQLite client, Python/SQLAlchemy server the previous registration, if available. This should reduce the amount of data entry needed following a network or registration failure. https://github.com/ucam-department-of-psychiatry/camcops/issues/104 + +- Provide more information if the app cannot delete the SQLite databases when a user + has forgotten their password. Fix a bug where if the initial password dialog was + aborted, the next attempt to set up a password would fail. + https://github.com/ucam-department-of-psychiatry/camcops/issues/346 From ec13b07c947d892a86504001a20f2664b2d12c3d Mon Sep 17 00:00:00 2001 From: Martin Burchell Date: Tue, 16 Apr 2024 16:23:18 +0100 Subject: [PATCH 5/7] Update actions to use Node.js 20 Node.js 16 actions are deprecated. Please update the following actions to use Node.js 20: actions/checkout@v3, actions/setup-python@v4. For more information see: https://github.blog/changelog/2023-09-22-github-actions-transitioning-from-node-16-to-node-20/. --- .github/workflows/build-and-install-packages.yml | 4 ++-- .github/workflows/build-qt.yml | 4 ++-- .github/workflows/cpp-tests.yml | 2 +- .github/workflows/database-upgrade-downgrade.yml | 4 ++-- .github/workflows/docker.yml | 2 +- .github/workflows/docs.yml | 4 ++-- .github/workflows/installer.yml | 2 +- .github/workflows/launch-cherrypy.yml | 4 ++-- .github/workflows/missing-migration-check.yml | 4 ++-- .github/workflows/precommit.yml | 4 ++-- .github/workflows/python-package-checks.yml | 4 ++-- .github/workflows/python-tests.yml | 4 ++-- .github/workflows/release.yml | 2 +- .github/workflows/report-missing-client-translations.yml | 4 ++-- 14 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.github/workflows/build-and-install-packages.yml b/.github/workflows/build-and-install-packages.yml index 7fbd55fad..5fc6484be 100644 --- a/.github/workflows/build-and-install-packages.yml +++ b/.github/workflows/build-and-install-packages.yml @@ -21,8 +21,8 @@ jobs: os: [ubuntu-20.04, ubuntu-22.04] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Change apt mirror diff --git a/.github/workflows/build-qt.yml b/.github/workflows/build-qt.yml index 194a3e9cb..d8d51f9dc 100644 --- a/.github/workflows/build-qt.yml +++ b/.github/workflows/build-qt.yml @@ -24,7 +24,7 @@ jobs: os: windows-2019 runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Free up disk space # The runner on Ubuntu will run out of space so we remove some of the things # we don't need. @@ -32,7 +32,7 @@ jobs: run: | set -eux -o pipefail ${GITHUB_WORKSPACE}/.github/scripts/free_up_disk_space.sh - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: 3.8 - name: Common Linux prerequisites diff --git a/.github/workflows/cpp-tests.yml b/.github/workflows/cpp-tests.yml index 55f29ae75..8529f0a26 100644 --- a/.github/workflows/cpp-tests.yml +++ b/.github/workflows/cpp-tests.yml @@ -20,7 +20,7 @@ jobs: cpp-tests: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Qt version check run: | set -euxo pipefail diff --git a/.github/workflows/database-upgrade-downgrade.yml b/.github/workflows/database-upgrade-downgrade.yml index 4e482b83b..fa143294f 100644 --- a/.github/workflows/database-upgrade-downgrade.yml +++ b/.github/workflows/database-upgrade-downgrade.yml @@ -14,8 +14,8 @@ jobs: database-upgrade-downgrade: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: 3.8 - name: Set up MySQL diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 872c3c23e..c8c2c3837 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -15,7 +15,7 @@ jobs: docker: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build run: | diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 9bb842da1..bea3c3f6a 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -22,8 +22,8 @@ jobs: python-version: "3.10" runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Change apt mirror diff --git a/.github/workflows/installer.yml b/.github/workflows/installer.yml index c1c5b2694..83b68918c 100644 --- a/.github/workflows/installer.yml +++ b/.github/workflows/installer.yml @@ -19,7 +19,7 @@ jobs: installer: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Run installer run: | set -eux -o pipefail diff --git a/.github/workflows/launch-cherrypy.yml b/.github/workflows/launch-cherrypy.yml index af6510396..d3c560656 100644 --- a/.github/workflows/launch-cherrypy.yml +++ b/.github/workflows/launch-cherrypy.yml @@ -19,8 +19,8 @@ jobs: os: [ubuntu-22.04] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Set up MySQL diff --git a/.github/workflows/missing-migration-check.yml b/.github/workflows/missing-migration-check.yml index 7cd200759..0884cac52 100644 --- a/.github/workflows/missing-migration-check.yml +++ b/.github/workflows/missing-migration-check.yml @@ -14,8 +14,8 @@ jobs: migration-check: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: 3.8 - name: Missing migration check diff --git a/.github/workflows/precommit.yml b/.github/workflows/precommit.yml index f8cf3ea31..148504297 100644 --- a/.github/workflows/precommit.yml +++ b/.github/workflows/precommit.yml @@ -12,8 +12,8 @@ jobs: precommit-checks: runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: 3.8 - name: Pre-commit checks diff --git a/.github/workflows/python-package-checks.yml b/.github/workflows/python-package-checks.yml index 27e6b2154..958ea5215 100644 --- a/.github/workflows/python-package-checks.yml +++ b/.github/workflows/python-package-checks.yml @@ -17,8 +17,8 @@ jobs: os: [ubuntu-20.04, ubuntu-22.04] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Python package checks diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index ae8895727..fb9b8f6bf 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -19,8 +19,8 @@ jobs: os: [ubuntu-20.04, ubuntu-22.04] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Change apt mirror diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e46b7d2d4..e85f1c643 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: contents: write steps: - name: Check out repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Work out tag id: vars run: echo ::set-output name=tag::${GITHUB_REF#refs/*/} diff --git a/.github/workflows/report-missing-client-translations.yml b/.github/workflows/report-missing-client-translations.yml index 7cefbadda..db3ac68bc 100644 --- a/.github/workflows/report-missing-client-translations.yml +++ b/.github/workflows/report-missing-client-translations.yml @@ -20,7 +20,7 @@ jobs: report-missing-client-translations: runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Qt version check run: | set -euxo pipefail @@ -34,7 +34,7 @@ jobs: target: desktop arch: gcc_64 archives: "qtbase qtdeclarative qttools qttranslations icu" - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: "3.10" - name: Report missing client translations From 69985daed268c954056266efb53b7f70e9e7f93d Mon Sep 17 00:00:00 2001 From: Martin Burchell Date: Tue, 16 Apr 2024 16:31:19 +0100 Subject: [PATCH 6/7] Update Danish --- tablet_qt/translations/camcops_da_DK.qm | Bin 228178 -> 228744 bytes tablet_qt/translations/camcops_da_DK.ts | 56 +++++++++++++++++------- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/tablet_qt/translations/camcops_da_DK.qm b/tablet_qt/translations/camcops_da_DK.qm index 8d36764901620a965bf6f5aaf315d0c241ae2ef3..1618b8f081cb221f37940509a76dcbf3f60987a9 100644 GIT binary patch delta 11952 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 delta 11532 zcmX9^2V9Ns7eCMQuKV8m-g_lmLJ5U33KB z;U^)R_?tg_<^L6*kI%W?@xIS<&i8!J_nhaA`eDrfY+P(>nL{MCB*CT+Y*(U{o~2f( zd=xei@9!p3dXrGU5|Q_25_o5#ZjDH&oJiE`EIzjo^*vAQ!}C%rIOGux$|hQsUTTGU zb%;iGAfes|Vv)GkHUn{ed6p7TiR?L|V>mawTGO#1R zQY+N8CF#mJe1Cqa6`UPN8F3RHYDLOH+_-Z%Dfm9G96-vWsYKOnNO?A&gf6d1XE{LB zy$Y3SmrO#(7_v@%Z6Q`}ES2}VLA2eLDwyGcmP@Jf0(YXdfmCB_A+dMyRCD?;;vHhC zR)a-E-(1K+JVI3C1J%y9Cmywj>U<6*!D9o}f8;^@#3yR#y%*P&$#vRf66_aK)Asm& zwjDM5y`Ol;J%4SNs^oFVvY2?=M%3Y|6>*P)pJKczSnz z>bDIWu}L6He*qWxxRCmXRv|K_Q2$~eKjs4sm|TZ=rRy|c9zaun59~+SR}{Fyn*^uN zG-%6i61?xy;N~I3zKx_1TP$co9F5Xv6TcHgV>^}*rT(N)SiY+gP1r6Fn_QnJ?QBBq zYE_!DGL+b)U<=J~|3o}JlV${l5qnUHW`=|k4Y8wHgW#Di4ao932w;0cbCZ3Eey^Z; zX>W)%^@lAX_T5bL(gCJ+O=3Yvn-KTDL0RvX65BkKPMh?^XGhb8j8NkB7gL^C1lQiAJa?7Y z=%;jLo1WOF%5>$w$HeNqr2N8MVlPVQR{BbOFN*H9KqzK>p`tkK`1UP&{tvFR$A{j; zgb{bnpieowiRFjU*BRA`TUKqQum52ObsE!m5j*;Mm42*CBlf;I{XG62p$KCXdV%-> z8^&bhdzFQZzeF}97c-&VbbK$9$%lFoTX&!74vZtdA)4t9;eB;HQ?G^-by>r#n`|Ps zx&|v3(vSG~r>xx6PsF|~W);7uk%dpX#_Fa=6OEt8oZkBpovFzhbVw%Z+>SY~o=ZHt z5o?rVB)-gzxhYMEF5hBq6&SJo?yOnIHekgbthrZBVjX(3mbZ2hZAfKpz9LQMS+fqI z<%uP!%770DziWNgP01zt9Lu`DP9Tb_%lfQDdbO$o z8v%QQ^|^z;8w)IG#%5wJ78bk)3+ynF4WIv*_=I>CGTxTB-6%F@;X>jr7g^|pK?uQC z7IwHF(Sd3#Tv&wP?`GjwHxpm|l}$YYk2Z*5b01sYlF+0E`vWR&J&G-g_(-hsJ+}BE zVtBMKTauqfbo~xnItwXx zok^@mx$O2JfNNDWyLT*r7_ZG9&$1=9Z4i4_D3H+fJ1bsZ9x=CLFY@{leTii+ z{WFMJ1+tgLU5IuxW^eoL24DPQ@3jPCnGe{vVP}YKO<_O0-;hu?j#)}B-2j^JvETK6 zlhEKAXTLrY9eu~;{m9RM^SM6f8_`f(u2q{$%<~u5k}Sj%zH_5X52AV*+<4gz;JU$0 z&-)U4^@Eqy0RubkaqC=EL}e^5-_e6u%Za>(nwJ-jS1j|_1`qygx7XlK;BfNX#T$4!lF;b~cUc!kY}_2)s07*YHkP|)AjawC zc=NO(WXX8mqG}al2F6>o`$#;*owu|D;e5+1wS40k-pUHuGx8Akcnc=&XKBRSl;-a; z-ZmqK=*R)yZrL3YT)lYvj$MhJt;cOM2@=hb*$_OX!|E>eE7;E0GMHVrSGQ4M9 zq-_&lK0rT;=xIkj_+=hZ-D-S9&N8B3Re6Y&KxEaIkCpw2W_9Odr-A!@D)7*{FH!#s z9ClJZ?=ie;`jvMTnz#spY4e^W;BRkX!Kev#OGXoSb>e zO@L_Ze|(eFop??dPu=(!Rc#jEx9cv^`fz?YqZg6=4Sw>&Bx2__@pCp17WS?A#WIzN z_g4AELkMA&JN(i*6Vb4B{Kk@DC}#iT_wEhE!UypCTWS$aUB@5KK8%o6;7=)o_>RW> zS?7rW(=;1i>_;Rt?8e{PJtFGr$v>dzaF+r6%LFgtV{-YIO#q+ISN`=)CQ*Ja|DJXP zJ1FEo4&p+FDE>179(f$ZOTr!zd;LUUzTo^G{RAloVB3}~Xd`f+noR`LF)(50e*`N? zKDKU)P_dH*c^)xSs2Ym=z5P_M>2{9?gezlI!>~Sp;sw4>Rf2v@E%0df{_q$ny zmfMi-V_FHVBJ7DRJS4QXr1l~<=ZMhe_HAN|y9-`Tfa;I!1Rp{%xo9K!yq!(-$xrCg zr8+{iMCj@cf?@?i-(%p1IsJvey4#5|?+HOR`-tsrCXC1|gZiE)jNX5lc;b2?v@nhM zl>da#qVL#XM=H``r%k&N0Ws30(fMTx3FZR1JVB^A@PPIQE+=JVYg zZ)_l};$J)EgpfL75(#bJ3aO(}b!WgOTjC!O%k3_t9sfjZOCMqH+^NL#dJBg)`4Vj^ z7LKe3sOIeztU4UZiNd@a}iE#ZUz~>SU9({8L{A-LT;cFurWo*>!=dVRD{Av ziCDd+!W}(47yL>nDqjRJ*A|MJwIKG{L3o%^1!dmyNqFRlyi_BF=ZAoWNPD691FBrx zm%{5g2}F}c;hj`O%(z$h{?wi5guU=fd`|pwhG_VM<~ki=0meG3M8i{1YVB2`w!I3G z-D=Tv4O#HNE@GLt_`NhqEE~L>n0q79`oat1b#{p5e7loiX+BV_^sWK%#X7M{e-WU& zCEE19K>VL+qD{Cb@!W}GO^-<8q0yq}Sc(GQIA9Q_z=->+myLL--7@q@AH4+^% zk=L4wSl0(32?`gT9MC6RlElWloC!5vbUoyRej-hD{gy{8w5ixMx(Zp?CzII9N>5bt zy4cp#gSdXJ=-mu17i`5YJ0#*=3dMk+r>NucVt0FlM8BofvgMv)PZ=Jnyg~fOW)DJm zK@8Fd6W={a462E89W9E(^vLV~I*TK0QA3h;iX%{E$^Tz*O!#7SP=mz@70-bAlIMsM zXW9X!%f*RvZlHY57N`91Csr|1oEC!5@7EHit?dc9Y!)L@k>m^ZE3o+I%7{X+i7&k>BMuWtq&5_>M=ZVWwJcub>#g*lI5nr1k zuJW~HlAzxsuKzI%Ez?SI)952;jarGD1F+J7IB{qFRARA}ORZqtT->=8`aSlgxXZ%> z4q7elzBP$>c$}F22n+Pc6AvVTu+}~hGy39&r;5dl6^QlCNbz9NJ`&spiAN6ICtkg= zn3ao#3>z<=uq^TiD)YrtYle_eF+sd^xIWR{p5mn(Xt<#*#5`v&V)MPktG$ju=eH2A zRkI~(<1XfpM0(aP7H^tSRxd0S9~edv-TWp#+g3tcGl<3ES0L3kim#ej5#_xU-ze~G zvyENrJJG#Facqt3#47D+cM*LK4m;6Su!E zS+$x#%zLs_Zcq|YNrqJUn*%XtPpQgid@r)0RAmF~Wq+yKxIt)A10=gmj>M}zl4|!v zwQM|Es$1wwJU>cmc>GCYiPpGD0khr{^YV~- z=73MWTcqBJGl?w-D78Y>5mLW)p}^E2DbO{NsE*~RH2lj>#AJaqs<@CSW4$z{#{r=8 zfi!Nk6I!XeumGLmx-_BQH0*qcG;zsn;u$4Uc%K~N=Z{KLL!k?5=SefR1B6E#O0&G- zDIb$G=jMH43Eic+=E}r6){^F>A0@UnTZ#()1MUV=)E;zFmKtTG7?&gx{2NKJThJyq z7%0UBxnjuBN{V~F2~4;}N?5EX%2A|Ms~C2+T3WRu6jyoR5&+A){tajvxX zQY4CsRjCymR!i&svCw7Tr4&dywy=Y=xhX>2WT}+eO(e9LFI~6<23z(`y1HW~-mfj)`T3`sIYPV-T8)^mW-NVzq8b-`hgqBpsKjIuz2xESb%= zWD&hvBP%mwh!ww(b;D8smc6pNvII@$N!jRd1A707TxK4GMo@}emFEz9v_iK1ftiu- zN7?E2Zeo{T$W6l&h&pwX+jYw#HY!bkpH=Uo9M$Fc|Z^@eCCZj zU~YR7nvIkPCnOSIHBJutgOy>eY;)9YogBHK4e_wM z@`6V8kXWg5%uf`p1(s4P*jAO}IshwZAL7Fi>+&IT{O8G-1x=L`5^Nzj*2_yr{2+ej zk(^j*02b(C`THWuzSOd~zaOvk*4R;kyhk2Iba1-7XMG0I&eQVVYcGg3TPYv506eGS%M#<4jRyJhJ13sWMXb}<LmUd_GhZTzdsmZl%#R`Q#>hE4Q;EuslFwQ@ zkzidYpKWp-U2)r)^2HDLh%Zf)|D6tsyjEYnbrysXSWmuPJ)5Z7JNZsm7oyhj@?BSe z^h!1PUPKc#CNt&xW;bHv4e~>&33113^2759#8a63~LFQp8JV= zz5HuCyC_m!TjXoV2}L@dM)dDFMQd>sz2E|+d=~2SWOt>)vBt#u6)BYlS`jOINU3r< z0y~aUsxm)f_3tY-ACIEU1}nBH2wnO-r6ysAw$Bu&f-s_Hx0MEIm7$=D6&LRf#P(cM zTyMbTW1A?gW@8-Z>8W@2w)CEZn37tZ^WIeVEcG z3xu?)Kp9x`0I?%Cl_3+s{q@|Gq3xf5S|=z&3%e1o^*?3!u_MI#UsOiy354)iqlBC< zPwd`(Wz@x=P{*1wK6^Xyrel?fN77Ngn<ae*A4t<2i74p?zl=46DRE#Iretran}&R62m2+L5 z_;iX`rvPQqS9e@*v$8Y?j7b%g#57Q~^?PO6Go<6`wu)u>`afU%tRz)TLfM_EtbVr) z;3!cx|7k3i2Pj)Zplm8-C_9wv5Fp=_9dSVOn+D3>Tw7E@i?Xj0b}AfD_U#Tr+kH#P zuudg5vzl_q>N`d{m6c=hvoVDFsbpoMXKepmIVrhe4EIGjeU*U+YFd;W3?QiK<5J6q z>Xft9Kn%*GQp*yDE0^!y#Av;*a?R=m@rFstwf9J?_^ZmluT~S?8mZh;0kX6s%KgR3 zNIzM5TI&PSYm@S-(ifuDpOjZSrV;DiQF-++pZLTW<&ADXQQ->ZZB2V(hb@K5J8liC zJ*Iq2Mf2I~u=2~{6J|P^PE7=-56{+VvptC&B3;=!_+ix*y7ETUZ*#P+{6j40Qg2-~ zAKdssiq8JQ5frWcx;l;*h*mVy)s2Dl`ZYjT_aVl6Rxvu~9_XH{e$zE=eUjM8t2+1a zcEl{+dYxyLTw?!q(|J`WB3{O<^V#J_d|$Y(lj}F)O}6U%_aUDr{?G+Xvn6Vnrt9O2 zooC$F^*v%u6gxsU@P7c=&#Jm1W1tJXy>!D?+9SsCy5Vg;5Z@fH8=Yw)+PG2|`bW^5 z-l3abluop3oo*(SkcE{@*3I4ZhRAoRZvHk`sNY$-NaY1au&;H|X$8ckLR~^OrsVcU zUE&WDvEa74qzc$c*V($H1}BJnRMV|}8bm^iYP#e#MbLC#bSZY23;N8{r8F1-Fb>kC ze0@sXvsjl}^DPFD9dv1}aGy$vx*f^>(Dz?GbUPlYkm1F;^pgNt)L7k~f8hEqOt)u0 zdc*auy1k2r5esjr+jn&u(Xkb}L*-#JZFGk{dJ!24N-bM4PnYG@9w#C@bf?SuqT%?g zJ2SQeG0$LKPVZ2nGUs$>10vC`AJm<_=!}Vro$lNd3tVfo=yJ22FxeQPyYxuFK=HTk zN?tf1Fx2 z7@QuUQ!7R3iQc?cZO3SsSawn!vQH7e@K|+hgV;YRRGoz7s100o%EJZs=c^5#;eaZ2 zkm}rKBe5J~-XX16&svdqBL=|_d7LO$v7>#UD zz2XXqju)sMH^TMNqS|EuTC65^YL^iuNT*=6d+J>9#6Gq6N{s~eLjC7H&UWfMtNrEx z6BnDS{kO-U^~z8O2t;gSmOAw28RF**YVhq|7*H0dBNi7BE7MdRk@Kf`eN;yt_aZi} zzeOGS*aI%_q>dT#5e>$Db!;nlG!(h&*bBBuleX%FEkiLE?5c)UuSL{;w;Jx{2!a`> z&TMuQv!lc6>_L&}^B1UdhauLM2MX!p8Yy#A!C-uY}qtv9I=mT1RP?M|nBEcnAO8sR+>(_SFSM$b<`1Nyrt;@?%|7o4x!D5dQOD}!Bx+V+~N$(sj z5lb1RZ@du2qI`+INrf{+4)gUbm-wR4#e0_TZ%5?vVdcXGe!~@Rj{i6IZ zJ@?f64+CaK)YbcM3nrmnguZJUz`1X)K41hGRvV`8G5iVSet-Rde=K>#V~6Mmyg;v( zeMcV{Itzn^EBZlMj&?ZQ0KSmgUnz!hfn(8R^>=2b5tK35di&uL?03h9$40? z)CyL8^dWcf_wt{mR;VybKc+u!tklqlZs?0i=`Q{F`3UvpIr@n$kWHO;>%%QS!2MY> z_0yuUqZWz!*;UJ9z!;;Cxa9^3)m0zqe;qOO(Jvf_5zF~0`q;rGM7DJ9p9$k(sw>IWWirM->Ba*s{`bG zd%a~#BnE-Ha{8@zaiP8|^xIISsK+OLTC?{+`)Ym0MueorKKo@6-P5nTu+YbGi<`=LK2YpWQ8+1H1OD$WvM1R2t)csM@Ux;i!p$OUNALN|Eh5G9sqRnQD2I(KM3}UnM^iN#?x~y~h z;<1}C0ePc;weJm1L=WlT7F(0x-c)FMies(7M9&E7swVb%`d4siY zGFq&!f9;uALxoq{F={DesQ5C1xO=RjQd|-^f2^VE&Yn0M9$=`3!%6yh)Zmb;LV$!D z>No@vE0=9>jBi2ow#eWV#)+j0hI-{d(Uyj>hWdwq%GKKp&ARj;-rUjP-Yl8e!@7o6 zgFMmqZ#8(JH)M1Rb~0wa&W3h2z(k+h2CuU>F=kIU_>A+zg~uB@ok4b3g&R7(Od!GW zn!$f-3h@=)4PC!uEY~{N(Eqs(hf$7(frfS{LjHz>)N|3~{r4Ay_gE@$W#zD>Dp> z#GynnRSb(FfTe!B4Xc{Dl2Bv0VcmcPqK+>O$%K&d<%VQyXN>E{7*eD^^?zm6KQD;y zNHC-vzz+BRXV_vJNZi!cu;qMXbh*zBySm|r^-YFd2Wk-&g&5KeP&m3xhIAWHZM7PP zJt|`Q^tEBnzRE=X>KOJZ%ZatvU^wsy;LXf694<2tAYW`a`~VB>lwmj#3UI#(H018E zfb$>5;zbb&)e8()6DYhLW4ek|FOk zR*2be%kr9F8S;i`dZJcl@DZY~Bek;UaKl-TH0$7cMA@gb@+YvMtyQ!NDVTihzoAuc z69n+A(Q0};C-%P?TFvv@i4WSX*=>CR#S@~{az+O=E?%qExG%uxs@3i62zyX#u-lsW zR5z_rJrAN<@tW&sSi1tv()t2E_}544I1U~#4c5HtqKeh)ta%>-fwWtvbrR>G`~9GG zzHo+Ui$(KKhf8&yT0od5vE6gEfQ8esLo2O&Z^U@j^inI-J*##9ifquyTF6=P?Z&ht<(SD*nJGF@;k*;gHXp{P&Tkg6{n^M%D zXzXe&oM(|x*-@L*3dLu98Eqbjh?Z2+=EniNeJxg6lpBiA#3@>g%{w#{ceR)gP$pxe zwAjl?Bd>#6Z2mQ(lrSy9^*gbem9!;$@xuXmT4FRXGWV^v>?}Z7wSu6OuPZt(mf^+ z+m@~ENdpsxrD_?q5F>4ecCb5Q_}X1NWQXsa_0$fH4Z}_^Xvf$jETD{btak}fh51_M zD>pn;6s2V?3?%v|Sv&C=p55?GJ5{JBdKs&oISj1ave9yLe27)3qUGlAf&Ra;S-Unk z3oTNicHIc!p{d%9d&7vvOIpF(ETS52T9MHNt+r8n6oeh@3DI7DHdsGiq}3j9*hNV)jlu82Ks%|z8u8+y}oH*_W@J-#zx(9grvd&qgBXk z%>NekF+URr$ z=)PkxI^{vpv?im|A7#_3ztL?O7A|cvHgk?ZPdLQbvMD?h8fk2K2HBzPEVV4LfzhWg z7VL+F8HDz)M!T=_?{fvx&_@6}%H`;`2c?Ke>r#BAw=KF$n=B#J+f#gh@Sc!VzT>j{>Z% ztDBUuZ-}+ZHEA>3gYlwFW%Ggh!Y8JRpO+Fls5ezQ?Ml3?lc~xY)DY3K%VZmi`o4d* zspfU;)cw85UfcvCvNzdlkXUu@ndfdQ<(g_lUI_ZgQTA z3)<8%xh%}UkgA%g(FTNY?kiK%vRBc#1+e8ro)t~q?>Q0ePd4=m z>W{;y)uw*y0NQ>brl1(KTy{>Tp(8fq*|1-x5vTGn^{QnGSpk(j&e=4n+Z8+yaMd*B z&&fw@k!h+=9`gTp8`HF_3B+qmHBIk@G~3?6wCKtvqH)2dMb99$j;=E;F+C;T?v-g- zm7dTAb4^Jl@YLQnrqypbB$use%kn2A7{8ddrG~*SHSKS%qL&ObW&B9Q*u9bIu=Rcn zubfSpP)>YwdDE$W>!AyLOs9LfT5#<4&~!D$g}54N%D3N-y#H>x-Uo#AE)7_8xXq$hU-h2h|{90#vi_t9YY+`yBiF8|Y-t@l4OU!l$o4(=EE!L>K z>F0JwP_?J&=TC5cLZqo=Bg*yl(`IHj4I`RxGiza~j2D?^wj`2-`oqma&mJV$-7^bg zaJYP@vRP_8g!tB9X1Po!$nceBZ3wVpyVPv*nN4h#Xto)GnC|RmuD%D=&s^7RXAgi`&EoZ!ieA?DUA!qD9| zH+wW*hxA)$Ztn*0RVp;M-wDMNG1Tm-;;g5jw%POGY*e@NX7491h z4OFgLVD=Ah4W7t0clSUxH1B2Zp7K9DM=;7k5)X7R5A=oY=3*YWqXY81t9c;4C$t}G4qWR?Y|v2iU^xc^ zhO?!XryVm7JNt)V?wE)FXo8|+ZyrGiRr7A<@hx#y^kTeu@~J|o4e93 z_L!4zq66}<_?p+Z*+jhjDRWB4BH~A4&0EHABz7szyd@G3i9}yD@2KUAYWL2(%i=-o z#(i`817~o3Z}VQqM!?2F^WI%oAi<30>=n~-z+g0=*@lr#55;`eDHp@6UFNfWI}@uE zWIkv68cBS%)Up)^&3Okv{lPECoAa;Y8I5^|%{Qw9y)Vj`3zj*9V3wJ03nm;g` CamcopsApp - + Configuring internal database Konfiguration af intern database @@ -471,12 +471,12 @@ Inkonsekvent database tilstand - + Decrypting databases... Dekryptering af databaser... - + Can't read system database; corrupted? encrypted? (This version of CamCOPS has had its encryption facilities disabled.) Kan ikke læse systemdatabasen; ødelagt? krypteret? (Denne version af CamCOPS har haft sine krypteringsfaciliteter deaktiveret.) @@ -491,7 +491,7 @@ Nej, jeg kan ikke huske kodeordet - + Upload? Upload? @@ -506,13 +506,13 @@ Ja, upload - - + + No, cancel Nej, annuller - + You did not select how you would like to use CamCOPS Du valgte ikke, hvordan du vil bruge CamCOPS @@ -527,7 +527,7 @@ Du kan ikke ændre tilstand, når der stadig er opgaver, der skal overføres - + Registering patient... Registrering af patient... @@ -614,7 +614,7 @@ Har du forbindelse til internettet? Prøv igen med fejllog - + You entered an incorrect password. Try again? Du indtastede en forkert adgangskode. Prøv igen? @@ -641,7 +641,33 @@ Alle poster, der ikke uploades til serveren, går tabt. Slet database? - + + CamCOPS could not delete its databases: + +%1 +Please try to delete these files manually and restart CamCOPS + + CamCOPS kunne ikke slette sine databaser: + +%1 +Prøv venligst at slette disse filer manuelt og genstart CamCOPS + + + + + Failed to delete file: +%1 +because of this error: +%2 + + Kunne ikke slette filen: +%1 +på grund af denne fejl: +%2 + + + + Enter app password Indtast programadgangskode @@ -701,7 +727,7 @@ Alle poster, der ikke uploades til serveren, går tabt. JEG ER IKKE ENIG - + OK. Goodbye. Okay. Farvel. @@ -711,7 +737,7 @@ Alle poster, der ikke uploades til serveren, går tabt. Du nægtede betingelserne. - + Uploading... Uploader … @@ -748,7 +774,7 @@ Flyt venligst, når det er muligt; dette reducerer mængden af patientidentifice Flyt - + Opening... Åbning... @@ -4556,7 +4582,7 @@ enig PatientRegistrationDialog - + Registration Registrering @@ -7558,7 +7584,7 @@ Tak! ValidatingLineEdit - + Valid Gyldig From e1046d0efe4c7126a36779a0ae076bdd6aca6392 Mon Sep 17 00:00:00 2001 From: Martin Burchell Date: Tue, 16 Apr 2024 16:33:33 +0100 Subject: [PATCH 7/7] Bump Flower to fix PVE-2024-99785 I'm a bit nervous of the major version change here and can't see any documentation relating to incompatibilities between versions. --- server/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/setup.py b/server/setup.py index 1211a6a30..f2513ab75 100644 --- a/server/setup.py +++ b/server/setup.py @@ -86,7 +86,7 @@ "Faker==4.1.1", # create fake data; for test and dummy database creation # FHIR export, our fork until https://github.com/smart-on-fhir/client-py/pull/105 is merged # noqa "fhirclient @ git+https://github.com/ucam-department-of-psychiatry/client-py@128bbe3c2194a51ba6ff8cf880ef2fdb9bfcc2d6#egg=fhirclient-4.0.0.1", # noqa: E501 - "flower==1.2.0", # monitor for Celery + "flower==2.0.1", # monitor for Celery "gunicorn==21.2.0", # web server (Unix only) "hl7==0.3.5", # For HL7 export # Celery dependency for Python <= 3.7; workaround import error