prepare = async (
  viewname,
  table,
  fields,
  { columns, layout, fixed, auto_save },
  { req, res },
  body,
  {
    getRowQuery,
    saveFileQuery,
    saveFileFromContentsQuery,
    optionsQuery,
    getRowByIdQuery,
  },
  remote
) => {
  const isRemote = !isWeb(req);
  const form = await getForm(
    table,
    viewname,
    columns,
    layout,
    body.id,
    req,
    isRemote
  );
  if (auto_save)
    form.onChange = `saveAndContinueDelayed(this, ${
      !isWeb(req) ? `'${form.action}'` : undefined
    }, event);`;

  Object.entries(body).forEach(([k, v]) => {
    const form_field = form.fields.find((f) => f.name === k);
    const tbl_field = fields.find((f) => f.name === k);
    if (tbl_field && !form_field && !fixed?.[`_block_${k}`]) {
      form.fields.push(new Field({ name: k, input_type: "hidden" }));
    }
  });
  setDateLocales(form, req.getLocale());
  await transformForm({
    form,
    table,
    req,
    row: body[table.pk_name]
      ? { [table.pk_name]: body[table.pk_name] }
      : undefined,
    getRowQuery,
    viewname,
    optionsQuery,
  });
  const cancel = body._cancel;
  await form.asyncValidate({
    ...body,
    _file_names: Object.keys(req.files || {}),
  });
  if (form.hasErrors && !cancel) {
    if (req.xhr) res.status(422);
    await form.fill_fkey_options(false, optionsQuery, req.user);
    const view = View.findOne({ name: viewname });

    res.sendWrap(
      { title: viewname, no_menu: view?.attributes?.no_menu },
      renderForm(form, req.csrfToken ? req.csrfToken() : false)
    );
    return null;
  }
  let row;
  const pk = fields.find((f) => f.primary_key);
  let id = pk.type.read(body[pk.name]);
  if (typeof id === "undefined") {
    const use_fixed = await fill_presets(table, req, fixed);
    row = { ...use_fixed, ...form.values };
  } else if (cancel) {
    row = getRowByIdQuery
      ? await getRowByIdQuery(id)
      : await table.getRow({ id }, { forUser: req.user, forPublic: !req.user });
  } else {
    row = { ...form.values };
  }
  for (const field of form.fields.filter((f) => f.isRepeat)) {
    delete row[field.name];
  }

  const file_fields = form.fields.filter((f) => f.type === "File");
  for (const field of file_fields) {
    if (!field.fieldviewObj?.isEdit || field.fieldviewObj?.isStream) continue;
    if (field.fieldviewObj?.setsFileId) {
      //do nothing
    } else if (field.fieldviewObj?.setsDataURL) {
      if (body[field.name]) {
        if (body[field.name].startsWith("data:")) {
          const path_to_serve = await saveFileQuery(
            body[field.name],
            field.id,
            field.fieldview,
            row
          );
          row[field.name] = path_to_serve;
        }
      }
    } else if (field.fieldviewObj?.editContent) {
      if (body[field.name]) {
        const path_to_serve = await saveFileFromContentsQuery(
          body[`_content_${field.name}`],
          field.id,
          field.fieldview,
          row,
          body[field.name],
          "utf8"
        );
        row[field.name] = path_to_serve;
      }
    } else if (req.files && req.files[field.name]) {
      if (!isWeb(req) && !remote && req.files[field.name].name) {
        throw new Error(
          "The mobile-app supports no local files, please use a remote table."
        );
      }
      if (isWeb(req)) {
        const file = await File.from_req_files(
          req.files[field.name],
          req.user ? req.user.id : null,
          (field.attributes && +field.attributes.min_role_read) || 1,
          field?.attributes?.folder
        );
        row[field.name] = file.path_to_serve;
      } else {
        const file = req.files[field.name];
        if (file) {
          const serverResp = await File.upload(req.files[field.name]);
          if (serverResp?.location) row[field.name] = serverResp.location;
        }
      }
    } else {
      delete row[field.name];
    }
  }
  return { form, row, pk, id };
}
preparations for the form and the data row
@param {*} viewname
@param {*} table table of the view
@param {*} fields all fields in table
@param {*} param3 columns, layout, fixed, auto_save
@param {*} param4  req, res
@param {*} body request body
@param {*} param6 getRowQuery, saveFileQuery, saveFileFromContentsQuery, optionsQuery, getRowByIdQuery
@param {*} remote
@returns null on error, { form, row, pk, id } on success