Skip to content
This repository has been archived by the owner on Aug 18, 2021. It is now read-only.

Deploy #27

Merged
merged 13 commits into from
Oct 4, 2020
Merged
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
3 changes: 2 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ tmp
node_modules
npm-debug.log
.vscode
redis.conf
redis.conf
.google-api-creds.json
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ node_modules
.env
vars.yml
.hokusai-tmp
.google-api-creds.json
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ FROM node:12.14-alpine

# Build environment variables
ARG SHEETS_URL
ARG G_CREDS
ARG ACCESS_KEY_ID
ARG SECRET_ACCESS_KEY
ARG REGION
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,21 @@ Team Nav started off as a hackathon project way back in 2015. It's evolved a lot
_For Artsy Employees_

1. Copy down the `.env` file from citadel (You'll need proper access)

```
aws s3 cp s3://artsy-citadel/dev/.env.team .env
```

2. Install dependencies and start the service in dev mode

```
yarn && yarn dev
```

## Deploying

Merged PRs to `artsy/team#master` are automatically deployed to staging; PRs from `staging` to `release` are automatically deployed to production. [Start a deploy...](https://github.com/artsy/team/compare/release...staging?expand=1)

## About Artsy

<a href="https://www.artsy.net/">
Expand Down
1 change: 1 addition & 0 deletions hokusai/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ services:
context: ../
args:
SHEETS_URL: "{{ SHEETS_URL }}"
G_CREDS: "{{ G_CREDS }}"
ACCESS_KEY_ID: "{{ ACCESS_KEY_ID }}"
SECRET_ACCESS_KEY: "{{ SECRET_ACCESS_KEY }}"
REGION: "{{ REGION }}"
Expand Down
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
"private": true,
"description": "",
"scripts": {
"write-creds": "node ./scripts/write-credentials",
"start": "next start",
"predev": "dotenv yarn write-creds",
"dev": "next dev",
"prebuild": "dotenv yarn write-creds",
"build": "next build",
"type-check": "tsc",
"logs:staging": "hokusai staging logs | grep '^{' | npx miami-vice",
Expand All @@ -18,6 +21,7 @@
"aws-sdk": "^2.668.0",
"csvtojson": "^2.0.10",
"date-fns": "^2.12.0",
"googleapis": "^59.0.0",
"isomorphic-unfetch": "^3.0.0",
"isotopes": "^0.6.0",
"jwt-decode": "^2.2.0",
Expand Down Expand Up @@ -48,6 +52,7 @@
"@types/sharp": "^0.25.0",
"@types/styled-components": "^4",
"@types/styled-system": "^5.1.10",
"dotenv-cli": "^4.0.0",
"next-transpile-modules": "^4.1.0",
"typescript": "^3.8.3",
"typescript-styled-plugin": "^0.15.0"
Expand Down
9 changes: 9 additions & 0 deletions scripts/write-credentials.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* This file writes out the google credentials required to access the google drive api to read our team images.
*/
const fs = require("fs");

fs.writeFileSync(
".google-api-creds.json",
Buffer.from(process.env.G_CREDS, "base64").toString("ascii")
);
82 changes: 48 additions & 34 deletions src/data/image.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
import sharp from "sharp";
import S3 from "aws-sdk/clients/s3";
import stream from "stream";
import { hash } from "utils";
import { google } from "googleapis";

const drive = google.drive({
version: "v3",
auth: new google.auth.GoogleAuth({
keyFile: "./.google-api-creds.json",
scopes: [
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/drive.appdata",
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/drive.metadata",
"https://www.googleapis.com/auth/drive.metadata.readonly",
"https://www.googleapis.com/auth/drive.photos.readonly",
"https://www.googleapis.com/auth/drive.readonly",
],
}),
});

const streamToS3 = (
s3: S3,
Expand All @@ -28,42 +44,40 @@ export async function resizeImage(
secretAccessKey: process.env.SECRET_ACCESS_KEY,
region: process.env.REGION,
});
if (imageUrl.href.includes("dropbox")) {
imageUrl.search = "?raw=1";
} else if (imageUrl.href.includes("drive.google.com")) {
const imageId = imageUrl.href.split("/file/d/")[1]?.split("/")[0];
if (!imageId) {
throw new Error(
`Invalid formatted google drive image url: ${imageUrl.href}`
);
}
imageUrl.href = "https://drive.google.com/a/artsymail.com/uc";
imageUrl.search = `?id=${imageId}`;

if (!imageUrl.href.startsWith("https://drive.google.com")) {
throw new Error(`Error processing ${imageUrl.href}, not a drive url`);
}

const imageId = imageUrl.href.split("/file/d/")[1]?.split("/")[0];

if (!imageId) {
throw new Error(
`Invalid formatted google drive image url: ${imageUrl.href}`
);
}

const resizer = sharp().rotate().resize(size, size);

return fetch(imageUrl.toString(), { redirect: "follow" }).then((imgRes) => {
return new Promise((resolve, reject) => {
if (!imgRes.headers.get("content-type")?.includes("image")) {
reject(`${imageUrl} resulted in invalid content type`);
return;
}
if (imgRes.status >= 400) {
reject(`${imageUrl} was not found`);
return;
}
(imgRes.body as any).pipe(resizer).pipe(
streamToS3(
s3,
`team/${hash(
imageUrl.href + "?size=" + size
)}.${imageUrl.pathname.split(".").pop()}`,
(err, data) => {
err ? reject(err) : resolve(data.Location);
}
)
);
});
const file = await drive.files.get(
{
fileId: imageId,
alt: "media",
},
{ responseType: "stream" }
);

const contentType = file.headers["content-type"];
const extension =
contentType.includes("image") && contentType.split("image/")[1];

if (!extension) throw new Error(`No valid extension for ${imageUrl.href}`);

return new Promise((resolve, reject) => {
file.data.pipe(resizer).pipe(
streamToS3(s3, `team/${imageId}-${size}.${extension}`, (err, data) => {
err ? reject(err) : resolve(data.Location);
})
);
});
}
4 changes: 3 additions & 1 deletion src/data/team.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const getResizedImageUrl = async (
return limit(() => resizeImage(new URL(imageUrl), size)).then(
async function afterResizingImage(resizedImageUrl) {
if (!resizedImageUrl) {
log.error(`No image URL provided`);
return;
}
log.info(`resized ${imageUrl} to ${size}`);
Expand Down Expand Up @@ -63,7 +64,8 @@ export const getMembers = memoize(async () => {
try {
member.profileImage = await getResizedImageUrl(member.headshot, 500);
member.avatar = await getResizedImageUrl(member.headshot, 200);
} catch {
} catch (error) {
log.error(error);
member.profileImage = "";
member.avatar = "";
}
Expand Down
Loading