Skip to content

Commit

Permalink
Garbage collection
Browse files Browse the repository at this point in the history
  • Loading branch information
baltpeter committed Nov 1, 2024
1 parent de25825 commit b7b6f12
Show file tree
Hide file tree
Showing 10 changed files with 105 additions and 2 deletions.
2 changes: 1 addition & 1 deletion assets/dsr-templates/en/access-data.typ
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ We do however publish the technical details about the app analyses, including th
=== 5. Period for which the personal data will be stored
Any files you may have uploaded to a proceeding are automatically deleted one week after the proceeding is completed (i.e. the developer has remedied the violations, or you have sent a complaint to the data protection authorities). \
Any files you may have uploaded to a proceeding are automatically deleted one week after the proceeding is completed (e.g. the developer has remedied the violations, or you have sent a complaint to the data protection authorities) or one year after the creation of the proceeding. \
You always have the option to request an immediate deletion of any files you have uploaded. You can do so at this page or by contacting us: https://www.tweasel.org/privacy/erasure-request/
The non-personal data is stored indefinitely.
Expand Down
3 changes: 2 additions & 1 deletion assets/dsr-templates/en/proceeding.typ
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,11 @@
== State
- Proceeding state: #descriptions.proceedingState.at(proceeding.state)
- Proceeding state: #descriptions.proceedingState.at(proceeding.state) (updated on: #proceeding.stateUpdatedOn)
- Complaint state: #descriptions.complaintState.at(proceeding.complaintState)
- Notice sent at: #if proceeding.noticeSent != none [#proceeding.noticeSent] else [_not yet_]
- Complaint sent at: #if proceeding.complaintSent != none [#proceeding.complaintSent] else [_not yet_]
- Expired: #if proceeding.expired != none [#proceeding.expired] else [_no_]
== Provided answers
Expand Down
2 changes: 2 additions & 0 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { defineConfig, envField, squooshImageService } from 'astro/config';
import preact from '@astrojs/preact';
import global from 'astro-global';

import './src/cron';

// https://astro.build/config
export default defineConfig({
output: 'server',
Expand Down
10 changes: 10 additions & 0 deletions dbschema/default.esdl
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ module default {

required state := (
'erased' if exists(.erased) else
'expired' if exists(.expired) else
'needsInitialAnalysis' if not exists(.initialAnalysis) and exists(.requestedAnalysis) else
'initialAnalysisFailed' if not exists(.initialAnalysis) and not exists(.requestedAnalysis) else
'initialAnalysisFoundNothing' if all(std::json_typeof(json_array_unpack(.initialAnalysis.trackHarResult)) = 'null') else
Expand All @@ -68,6 +69,14 @@ module default {
'awaitingComplaint' if not exists(.complaintSent) and any(std::json_typeof(json_array_unpack(.secondAnalysis.trackHarResult)) != 'null') else
'complaintSent'
);
required stateUpdatedOn: datetime {
rewrite update using (
datetime_of_statement()
if __specified__.state and __old__.state != __subject__.state
else __old__.stateUpdatedOn
);
default := datetime_current();
};
required complaintState := (
'notYet' if .state != 'awaitingComplaint' else
'askIsUserOfApp' if not exists(.complainantIsUserOfApp) else
Expand Down Expand Up @@ -96,6 +105,7 @@ module default {
complaintSent: datetime;

erased: datetime;
expired: datetime;

multi uploads := .<proceeding[is MessageUpload];
single requestedAnalysis: RequestedAnalysis {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"@myriaddreamin/typst.ts": "^0.4.1",
"astro": "4.11.0",
"astro-global": "^1.2.1",
"cron": "^3.1.8",
"edgedb": "^1.5.7",
"hash-wasm": "^4.11.0",
"jose": "^5.4.1",
Expand Down
8 changes: 8 additions & 0 deletions src/components/ProceedingLandingPage/Expired.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
import { t } from '../../i18n/server';
import Base from '../../layouts/base.astro';
---

<Base title={t('proceeding-landing-expired', 'heading')}>
{t('proceeding-landing-expired', 'explanation')}
</Base>
56 changes: 56 additions & 0 deletions src/cron.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* eslint-disable no-console */
import { CronJob } from 'cron';
import { client, e } from './lib/db';

const proceedingCompletedStates = [
'complaintSent',
'secondAnalysisFoundNothing',
'secondAnalysisFailed',
'initialAnalysisFoundNothing',
'initialAnalysisFailed',
'expired',
'erased',
];

// Garbage collection
new CronJob('08 12 03 * * *', async () => {
console.log('Running garbage collection...');

// Proceedings expired after one year.
const oneYearAgo = new Date();
oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1);

const expiredProceedings = await e
.update(e.Proceeding, (p) => ({
filter: e.all(
e.set(
e.op(p.state, 'not in', e.set(...proceedingCompletedStates)),
e.op(p.createdOn, '<=', oneYearAgo),
),
),

set: { expired: e.datetime_current() },
}))
.run(client);
console.log('Expired', expiredProceedings.length, 'proceedings.');

// Uploads of completed proceedings are deleted after one week.
const oneWeekAgo = new Date();
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);

const deletedCompletedUploads = await e
.delete(e.MessageUpload, (u) => ({
filter: e.all(
e.set(
e.op(u.proceeding.state, 'in', e.set(...proceedingCompletedStates)),
e.op(u.proceeding.stateUpdatedOn, '<=', oneWeekAgo),
),
),
}))
.run(client);
console.log('Deleted', deletedCompletedUploads.length, 'uploads of completed proceedings.');

console.log('Finished garbage collection.');
console.log();
}).start();
/* eslint-enable no-console */
4 changes: 4 additions & 0 deletions src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@
"heading": "You cannot continue with this proceeding",
"explanation": "We have removed your personal information from this proceeding because you have sent us an erasure request for it. You can thus no longer continue with this proceeding."
},
"proceeding-landing-expired": {
"heading": "This proceeding has expired",
"explanation": "This proceeding has expired because it is older than one year. We have removed any personal information that may have been uploaded to this proceeding. You can start a new analysis for the same app if you want."
},

"send-notice": {
"heading": "Send notice to developer",
Expand Down
3 changes: 3 additions & 0 deletions src/pages/p/[token]/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import SecondAnalysisFoundNothing from '../../../components/ProceedingLandingPag
import AwaitingComplaint from '../../../components/ProceedingLandingPage/AwaitingComplaint.astro';
import ComplaintSent from '../../../components/ProceedingLandingPage/ComplaintSent.astro';
import Erased from '../../../components/ProceedingLandingPage/Erased.astro';
import Expired from '../../../components/ProceedingLandingPage/Expired.astro';
const { token } = Astro.params;
if (!token) throw new Error('This should never happen.');
Expand Down Expand Up @@ -54,6 +55,8 @@ if (!isValidProceedingState(state)) throw new Error('This should never happen.')
<ComplaintSent complaintType={proceeding.complaintType!} />
) : state === 'erased' ? (
<Erased />
) : state === 'expired' ? (
<Expired />
) : (
''
)
Expand Down
18 changes: 18 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1292,6 +1292,11 @@
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==

"@types/luxon@~3.4.0":
version "3.4.2"
resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-3.4.2.tgz#e4fc7214a420173cea47739c33cdf10874694db7"
integrity sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==

"@types/mdast@^4.0.0":
version "4.0.4"
resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.4.tgz#7ccf72edd2f1aa7dd3437e180c64373585804dd6"
Expand Down Expand Up @@ -2340,6 +2345,14 @@ cosmiconfig@^7.0.0:
path-type "^4.0.0"
yaml "^1.10.0"

cron@^3.1.8:
version "3.1.8"
resolved "https://registry.yarnpkg.com/cron/-/cron-3.1.8.tgz#0def028942596ee528879a1251e1c612b9afc22b"
integrity sha512-45bqmAOSd/XB5JJWfV1W59fFEzqgNNWmOYQZVcw0sfyQqU35HFdVfTsr2xzlqWoTAfspRrvK0lSSLj8Pj9YmpQ==
dependencies:
"@types/luxon" "~3.4.0"
luxon "~3.5.0"

cross-dirname@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/cross-dirname/-/cross-dirname-0.1.0.tgz#b899599f30a5389f59e78c150e19f957ad16a37c"
Expand Down Expand Up @@ -4735,6 +4748,11 @@ lru-cache@^5.1.1:
dependencies:
yallist "^3.0.2"

luxon@~3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/luxon/-/luxon-3.5.0.tgz#6b6f65c5cd1d61d1fd19dbf07ee87a50bf4b8e20"
integrity sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==

magic-string@0.30.5:
version "0.30.5"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.5.tgz#1994d980bd1c8835dc6e78db7cbd4ae4f24746f9"
Expand Down

0 comments on commit b7b6f12

Please sign in to comment.