diff --git a/src/framework/processing/py/port/api/props.py b/src/framework/processing/py/port/api/props.py index 42bf8c3b..4b586c0b 100644 --- a/src/framework/processing/py/port/api/props.py +++ b/src/framework/processing/py/port/api/props.py @@ -146,12 +146,14 @@ class PropsUIPromptConsentForm: Tables to be shown to the participant prior to donation. Attributes: + id (str): will be used as part of the filename when the data is stored tables (list[PropsUIPromptConsentFormTable]): A list of tables. meta_tables (list[PropsUIPromptConsentFormTable]): A list of optional tables, for example for logging data. description (Optional[Translatable]): Optional description of the consent form. donate_question (Optional[Translatable]): Optional donation question. donate_button (Optional[Translatable]): Optional text for the donate button. """ + id: str tables: list[PropsUIPromptConsentFormTable] meta_tables: list[PropsUIPromptConsentFormTable] description: Optional[Translatable] = None @@ -191,6 +193,7 @@ def toDict(self): """ dict = {} dict["__type__"] = "PropsUIPromptConsentForm" + dict["id"] = self.id dict["tables"] = self.translate_tables() dict["metaTables"] = self.translate_meta_tables() dict["description"] = self.description and self.description.toDict() diff --git a/src/framework/processing/py/port/helpers/port_helpers.py b/src/framework/processing/py/port/helpers/port_helpers.py index 8694123b..606dfe63 100644 --- a/src/framework/processing/py/port/helpers/port_helpers.py +++ b/src/framework/processing/py/port/helpers/port_helpers.py @@ -99,12 +99,18 @@ def generate_file_prompt(extensions: str) -> props.PropsUIPromptFileInput: return props.PropsUIPromptFileInput(description, extensions) -def generate_review_data_prompt(description: props.Translatable, table_list: list[props.PropsUIPromptConsentFormTable]) -> props.PropsUIPromptConsentForm: +def generate_review_data_prompt( + id: str, + description: props.Translatable, + table_list: list[props.PropsUIPromptConsentFormTable] +) -> props.PropsUIPromptConsentForm: """ Generates a data review form with a list of tables and a description, including default donate question and button. - The participant can review these tables before they will be send to the researcher. + The participant can review these tables before they will be send to the researcher. If the participant consents to sharing the data + the data will be stored at the configured storage location. Args: + id (str): will be used as part of the filename when the data is stored table_list (list[props.PropsUIPromptConsentFormTable]): A list of consent form tables to be included in the prompt. description (props.Translatable): A translatable description text for the consent prompt. @@ -123,7 +129,8 @@ def generate_review_data_prompt(description: props.Translatable, table_list: lis }) return props.PropsUIPromptConsentForm( - table_list, + id=id, + tables=table_list, meta_tables=[], description=description, donate_question=donate_question, diff --git a/src/framework/processing/py/port/script.py b/src/framework/processing/py/port/script.py index dd1fb087..27f2d89c 100644 --- a/src/framework/processing/py/port/script.py +++ b/src/framework/processing/py/port/script.py @@ -51,12 +51,12 @@ def process(session_id: str): # Show this data to the participant in a table on screen # The participant can now decide to donate extracted_data = extract_the_data_you_are_interested_in(file_prompt_result.value) - consent_prompt = ph.generate_review_data_prompt(REVIEW_DATA_DESCRIPTION, extracted_data) - consent_prompt_result = yield ph.render_page(REVIEW_DATA_HEADER, consent_prompt) - - # If the participant wants to donate the data gets donated - if consent_prompt_result.__type__ == "PayloadJSON": - yield ph.donate(f"{session_id}-{platform_name}", consent_prompt_result.value) + consent_prompt = ph.generate_review_data_prompt( + id=f"{session_id}", # will be used as part of the file name when the data is stored + description=REVIEW_DATA_DESCRIPTION, + table_list=extracted_data + ) + yield ph.render_page(REVIEW_DATA_HEADER, consent_prompt) break diff --git a/src/framework/processing/worker_engine.ts b/src/framework/processing/worker_engine.ts index 9d4d6a99..dcfb5b74 100755 --- a/src/framework/processing/worker_engine.ts +++ b/src/framework/processing/worker_engine.ts @@ -1,5 +1,5 @@ import { CommandHandler, ProcessingEngine } from '../types/modules' -import { CommandSystemEvent, isCommand, Response } from '../types/commands' +import { CommandSystemEvent, CommandSystemDonate, isCommand, Response, PayloadDonate } from '../types/commands' export default class WorkerProcessingEngine implements ProcessingEngine { sessionId: String @@ -88,9 +88,32 @@ export default class WorkerProcessingEngine implements ProcessingEngine { handleRunCycle (command: any): void { if (isCommand(command)) { this.commandHandler.onCommand(command).then( - (response) => this.nextRunCycle(response), + (response) => { + switch(response.payload.__type__) { + case "PayloadDonate": + const donateCommand = constructDonateCommand(response.payload) + this.commandHandler.onCommand(donateCommand).then( + (response) => { + this.nextRunCycle(response) + } + ) + break + + default: + this.nextRunCycle(response) + } + }, () => {} ) } } } + +function constructDonateCommand(payload: PayloadDonate) { + const donateCommand: CommandSystemDonate = { + "__type__": "CommandSystemDonate", + "key": payload.key, + "json_string": payload.value, + } + return donateCommand +} diff --git a/src/framework/types/commands.ts b/src/framework/types/commands.ts index 8404085a..5a1a89b0 100644 --- a/src/framework/types/commands.ts +++ b/src/framework/types/commands.ts @@ -44,7 +44,8 @@ export type PayloadResolved = PayloadString | PayloadFile | PayloadFileArray | - PayloadJSON + PayloadJSON | + PayloadDonate export interface PayloadVoid { __type__: 'PayloadVoid' @@ -79,6 +80,12 @@ export function isPayloadJSON (arg: any): arg is PayloadJSON { return isInstanceOf(arg, 'PayloadJSON', ['value']) } +export interface PayloadDonate { + __type__: 'PayloadDonate' + value: string + key: string +} + export type Command = CommandUI | CommandSystem diff --git a/src/framework/types/prompts.ts b/src/framework/types/prompts.ts index e17f0231..c857aed8 100644 --- a/src/framework/types/prompts.ts +++ b/src/framework/types/prompts.ts @@ -72,11 +72,12 @@ export interface PropsUIPromptConsentForm { description?: Text donateQuestion?: Text donateButton?: Text + id: string tables: PropsUIPromptConsentFormTable[] metaTables: PropsUIPromptConsentFormTable[] } export function isPropsUIPromptConsentForm(arg: any): arg is PropsUIPromptConsentForm { - return isInstanceOf(arg, "PropsUIPromptConsentForm", ["tables", "metaTables"]) + return isInstanceOf(arg, "PropsUIPromptConsentForm", ["id", "tables", "metaTables"]) } export interface PropsUIPromptConsentFormTable { diff --git a/src/framework/visualisation/react/ui/prompts/consent_form.tsx b/src/framework/visualisation/react/ui/prompts/consent_form.tsx index 5e0e7ceb..8be0a412 100644 --- a/src/framework/visualisation/react/ui/prompts/consent_form.tsx +++ b/src/framework/visualisation/react/ui/prompts/consent_form.tsx @@ -26,7 +26,7 @@ export const ConsentForm = (props: Props): JSX.Element => { useUnloadWarning() const [tables, setTables] = useState(() => parseTables(props.tables)) const [metaTables, setMetaTables] = useState(() => parseTables(props.metaTables)) - const { locale, resolve } = props + const { locale, resolve, id } = props const { description, donateQuestion, donateButton, cancelButton } = prepareCopy(props) const [isDonating, setIsDonating] = useState(false) @@ -119,7 +119,7 @@ export const ConsentForm = (props: Props): JSX.Element => { function handleDonate(): void { setIsDonating(true) const value = serializeConsentData() - resolve?.({ __type__: "PayloadJSON", value }) + resolve?.({ __type__: "PayloadDonate", "value": value, "key": id }) } function handleCancel(): void {