/*
This is a one-off script to add type prefixes to object keys that don't have one.
*/

const process = require("process");
const args = require("commander");
const { Client } = require("pg");
const moment = require("moment");
const uuidv4 = require("uuid/v4");
const winston = require("winston");

const config = require("./config");
const modelsUtil = require("./models/util/util");

// Define the types of object keys that will be considered for pruning.
const keyTypes = Object.freeze([
  { prefix: "f", table: "Files", column: "fileKey" },
  { prefix: "raw", table: "Recordings", column: "rawFileKey" },
  { prefix: "rec", table: "Recordings", column: "fileKey" }
]);

async function main() {
  args
    .option("--config <path>", "Configuration file", "./config/app.js")
    .option("--delete", "Actually delete objects (dry run by default)")
    .parse(process.argv);

  config.loadConfig(args.config);

  const pgClient = await pgConnect();
  const s3 = modelsUtil.openS3();

  for (const kt of keyTypes) {
    const rows = await loadDBKeys(pgClient, kt.table, kt.column);
    const desiredPrefix = kt.prefix + "/";
    for (const [id, key] of rows) {
      if (!key.startsWith(desiredPrefix)) {
        const newKey = makeKey(kt.prefix);
        logger.info(`${kt.table}[${id}]: ${kt.column} "${key}" => "${newKey}"`);
        try {
          await copyObject(s3, config.s3.bucket, key, newKey);
          await updateDBKey(pgClient, kt.table, id, kt.column, newKey);
          await deleteObject(s3, config.s3.bucket, key);
        } catch (e) {
          logger.error(e.message);
        }
      }
    }
  }
}

function makeKey(prefix) {
  return prefix + "/" + moment().format("YYYY/MM/DD/") + uuidv4();
}

async function pgConnect() {
  const dbconf = config.database;
  const client = new Client({
    host: dbconf.host,
    port: dbconf.port,
    user: dbconf.username,
    password: dbconf.password,
    database: dbconf.database
  });
  await client.connect();
  return client;
}

async function loadDBKeys(client, table, column) {
  const res = await client.query({
    text: `select id, "${column}" as k from "${table}" where "${column}" is not NULL`,
    rowMode: "array"
  });
  return res.rows;
}

async function updateDBKey(client, table, id, column, newKey) {
  await client.query({
    text: `update "${table}" set "${column}"=$2 where id = $1`,
    values: [id, newKey]
  });
}

async function copyObject(s3, bucket, srcKey, dstKey) {
  const params = {
    CopySource: bucket + "/" + srcKey,
    Bucket: bucket,
    Key: dstKey
  };
  await s3.copyObject(params).promise();
}

async function deleteObject(s3, bucket, key) {
  const params = {
    Bucket: bucket,
    Key: key
  };
  await s3.deleteObject(params).promise();
}

const logger = new winston.Logger({
  transports: [
    new winston.transports.Console({
      timestamp: function() {
        return moment().format();
      },
      colorize: true
    })
  ]
});

main()
  .catch(logger.error)
  .then(() => {
    process.exit(0);
  });

@@ -1141,16 +1141,20 @@
 %5Bid, key
+, dt
 %5D of row
@@ -1154,24 +1154,24 @@
  of rows) %7B%0A
-
       if (!k
@@ -1242,16 +1242,20 @@
 t.prefix
+, dt
 );%0A     
@@ -1647,16 +1647,20 @@
 y(prefix
+, dt
 ) %7B%0A  re
@@ -1676,22 +1676,16 @@
 ix +
- %22/%22 +
  moment(
 ).fo
@@ -1672,32 +1672,34 @@
 prefix + moment(
+dt
 ).format(%22YYYY/M
@@ -1692,16 +1692,17 @@
 format(%22
+/
 YYYY/MM/
@@ -2124,13 +2124,21 @@
 mn%7D%22
- as k
+, %22createdAt%22
  fro

Use source entity date when setting new object keys