Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add liquid templates to filename #266

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"express-winston": "^2.4.0",
"hipchatter": "^1.0.0",
"jira-client": "^6.4.1",
"liquidjs": "^8.5.2",
"mailchimp": "^1.2.0",
"node-marketo-rest": "^0.7.0",
"nodemailer": "^5.1.1",
Expand Down
6 changes: 1 addition & 5 deletions src/actions/amazon/amazon_s3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,7 @@ export class AmazonS3Action extends Hub.Action {

const s3 = this.amazonS3ClientFromRequest(request)

const filename = request.formParams.filename || request.suggestedFilename()

if (!filename) {
throw new Error("Couldn't determine filename.")
}
const filename = await request.templatedFilename(request.formParams.filename)

const bucket = request.formParams.bucket

Expand Down
2 changes: 1 addition & 1 deletion src/actions/azure/azure_storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class AzureStorageAction extends Hub.Action {
throw "Need Azure container."
}

const fileName = request.formParams.filename || request.suggestedFilename()
const fileName = await request.templatedFilename(request.formParams.filename)
const container = request.formParams.container

if (!fileName) {
Expand Down
2 changes: 1 addition & 1 deletion src/actions/dropbox/dropbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class DropboxAction extends Hub.OAuthAction {
params = []

async execute(request: Hub.ActionRequest) {
const filename = request.formParams.filename
const filename = await request.templatedFilename(request.formParams.filename)
const directory = request.formParams.directory
const ext = request.attachment!.fileExtension

Expand Down
6 changes: 1 addition & 5 deletions src/actions/google/google_cloud_storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,7 @@ export class GoogleCloudStorageAction extends Hub.Action {
throw "Need Google Cloud Storage bucket."
}

const filename = request.formParams.filename || request.suggestedFilename()

if (!filename) {
throw new Error("Couldn't determine filename.")
}
const filename = await request.templatedFilename(request.formParams.filename)

const gcs = this.gcsClientFromRequest(request)
const file = gcs.bucket(request.formParams.bucket)
Expand Down
2 changes: 1 addition & 1 deletion src/actions/sendgrid/sendgrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class SendGridAction extends Hub.Action {
if (!request.formParams.to) {
throw "Needs a valid email address."
}
const filename = request.formParams.filename || request.suggestedFilename() as string
const filename = await request.templatedFilename(request.formParams.filename)
const plan = request.scheduledPlan
const subject = request.formParams.subject || (plan && plan.title ? plan.title : "Looker")
const from = request.formParams.from ? request.formParams.from : "Looker <noreply@lookermail.com>"
Expand Down
2 changes: 1 addition & 1 deletion src/actions/sftp/sftp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class SFTPAction extends Hub.Action {
throw "Needs a valid SFTP address."
}
const data = request.attachment.dataBuffer
const fileName = request.formParams.filename || request.suggestedFilename() as string
const fileName = await request.templatedFilename(request.formParams.filename)
const remotePath = Path.join(parsedUrl.pathname, fileName)

client.put(data, remotePath)
Expand Down
6 changes: 5 additions & 1 deletion src/actions/slack/slack.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as Hub from "../../hub"

import * as winston from "winston"

import { WebClient } from "@slack/client"

interface Channel {
Expand Down Expand Up @@ -29,6 +31,8 @@ https://github.com/looker/actions/blob/master/src/actions/slack/README.md`,

async execute(request: Hub.ActionRequest) {

winston.info(`request: ${JSON.stringify(request)}`)

if (!request.attachment || !request.attachment.dataBuffer) {
throw "Couldn't get data from attachment."
}
Expand All @@ -37,7 +41,7 @@ https://github.com/looker/actions/blob/master/src/actions/slack/README.md`,
throw "Missing channel."
}

const fileName = request.formParams.filename || request.suggestedFilename()
const fileName = await request.templatedFilename(request.formParams.filename)

const options = {
file: request.attachment.dataBuffer,
Expand Down
14 changes: 13 additions & 1 deletion src/hub/action_request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { PassThrough, Readable } from "stream"
import * as winston from "winston"
import { truncateString } from "./utils"

import Liquid from "liquidjs"

import {
DataWebhookPayload,
DataWebhookPayloadType as ActionType,
Expand Down Expand Up @@ -341,14 +343,24 @@ export class ActionRequest {
})
}

async templatedFilename(template?: string) {
if (template) {
const engine = new Liquid()
const filename = await engine.parseAndRender(template, this.scheduledPlan)
return sanitizeFilename(filename)
}
return this.suggestedFilename()
}

suggestedFilename() {
if (this.attachment) {
if (this.scheduledPlan && this.scheduledPlan.title) {
return sanitizeFilename(`${this.scheduledPlan.title}.${this.attachment.fileExtension}`)
} else {
return sanitizeFilename(`looker_file_${Date.now()}.${this.attachment.fileExtension}`)
return sanitizeFilename(`looker_file_${new Date().toISOString()}.${this.attachment.fileExtension}`)
}
}
return sanitizeFilename(`looker_file_${new Date().toISOString()}`)
}

/** creates a truncated message with a max number of lines and max number of characters with Title, Url,
Expand Down
1 change: 1 addition & 0 deletions test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ winston.remove(winston.transports.Console)

import "../src/actions/index"

import "./test_action_request"
import "./test_action_response"
import "./test_actions"
import "./test_server"
Expand Down
89 changes: 89 additions & 0 deletions test/test_action_request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import * as chai from "chai"
import * as sinon from "sinon"

import * as sanitizeFilename from "sanitize-filename"

import { ActionRequest} from "../src/hub"

describe("ActionRequest template filename", () => {

const now = new Date()
let clock: any
beforeEach(() => {
clock = sinon.useFakeTimers(now.getTime())
})

afterEach(() => {
clock.restore()
})

const request = new ActionRequest()
request.attachment = {
dataBuffer: Buffer.from("1,2,3,4", "utf8"),
fileExtension: "csv",
}
request.scheduledPlan = {
url: "looker_url",
title: "Looker_title",
query: {
id: 1,
model: "looker_model",
view: "looker_view",
fields: ["a", "b"],
pivots: ["pivot_a"],
fill_fields: null,
filter_expression: null,
filters: {
x: "xvalue",
y: "yvalue",
},
sorts: ["a"],
limit: "500",
column_limit: "10",
total: false,
row_total: null,
runtime: 10,
vis_config: null,
filter_config: null,
visible_ui_sections: null,
slug: null,
dynamic_fields: null,
client_id: null,
share_url: null,
url: "looker_url",
expanded_share_url: null,
query_timezone: "",
has_table_calculations: false,
can: {
run: true,
},
},
}

it("template works with template, a schedule plan and query", async () => {
const filename = await request.templatedFilename(`{{ title | downcase }}-{{ query.filters.x }}.csv`)
chai.expect(filename)
.to.equal("looker_title-xvalue.csv")
})

it("template works referring to a date format not from query", async () => {
const filename = await request.templatedFilename(`{{ "now" | date: "%Y-%m-%d" }}.csv`)
chai.expect(filename)
.to.equal(`${new Date().toISOString().slice(0, 10)}.csv`)
})

it("returns suggested without template", async () => {
const filename = await request.templatedFilename()
chai.expect(filename)
.to.equal(`Looker_title.csv`)
})

it("returns suggested without template schedulePlan", async () => {
const emptyRequest = new ActionRequest()

const filename = await emptyRequest.templatedFilename()
chai.expect(filename)
.to.equal(sanitizeFilename(`looker_file_${new Date().toISOString()}`))
})

})
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2653,6 +2653,11 @@ levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"

liquidjs@^8.5.2:
version "8.5.2"
resolved "https://registry.yarnpkg.com/liquidjs/-/liquidjs-8.5.2.tgz#b44071f48dfb7f7939d88c7912aee71bd1b4450d"
integrity sha512-ZeTeytJNkos0Xhbu3XeGEPbMBMhzJpr9ijIJzZr5FpWp7VS4t/+FDXMpxpKtzRaNc3ah30dhrSxVdCphOaNrlw==

load-json-file@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8"
Expand Down