Skip to content

Commit

Permalink
[ACTION] Unsplash - Search Photos, Get Photo (#11939)
Browse files Browse the repository at this point in the history
* Tested components

* pnpm-lock.yaml
  • Loading branch information
jcortes committed May 15, 2024
1 parent 9a188c6 commit 473f97d
Show file tree
Hide file tree
Showing 7 changed files with 345 additions and 4 deletions.
41 changes: 41 additions & 0 deletions components/unsplash/actions/get-photo/get-photo.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import app from "../../unsplash.app.mjs";

export default {
key: "unsplash-get-photo",
name: "Get Photo",
description: "Get a specific photo from Unsplash. [See the documentation](https://unsplash.com/documentation#get-a-photo)",
version: "0.0.1",
type: "action",
props: {
app,
photoId: {
propDefinition: [
app,
"photoId",
],
},
},
methods: {
getPhoto({
photoId, ...args
} = {}) {
return this.app._makeRequest({
path: `/photos/${photoId}`,
...args,
});
},
},
async run({ $ }) {
const {
getPhoto,
photoId,
} = this;
const response = await getPhoto({
$,
photoId,
});

$.export("$summary", `Successfully retrieved photo with ID \`${response.id}\``);
return response;
},
};
74 changes: 74 additions & 0 deletions components/unsplash/actions/search-photos/search-photos.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import constants from "../../common/constants.mjs";
import app from "../../unsplash.app.mjs";

export default {
key: "unsplash-search-photos",
name: "Search Photos",
description: "Get a single page of photo results for a query. [See the documentation](https://unsplash.com/documentation#search-photos)",
version: "0.0.1",
type: "action",
props: {
app,
query: {
type: "string",
label: "Query",
description: "Search terms.",
},
contentFilter: {
type: "string",
label: "Content Filter",
description: "Limit results by content safety. Valid values are `low` and `high`.",
optional: true,
options: constants.CONTENT_FILTERS,
},
color: {
type: "string",
label: "Color",
description: "Filter results by color. Valid values are: `black_and_white`, `black`, `white`, `yellow`, `orange`, `red`, `purple`, `magenta`, `green`, `teal`, and `blue`.",
optional: true,
options: constants.COLOR_OPTIONS,
},
orientation: {
type: "string",
label: "Orientation",
description: "Filter by photo orientation. Optional. (Valid values: `landscape`, `portrait`, `squarish`)",
optional: true,
options: constants.ORIENTATION_OPTIONS,
},
},
methods: {
searchPhotos(args = {}) {
return this.app._makeRequest({
path: "/search/photos",
...args,
});
},
},
async run({ $ }) {
const {
app,
searchPhotos,
query,
contentFilter,
color,
orientation,
} = this;

const photos = await app.paginate({
resourcesFn: searchPhotos,
resourcesFnArgs: {
$,
params: {
query,
content_filter: contentFilter,
color,
orientation,
},
},
resourceName: "results",
});

$.export("$summary", `Successfully retrieved \`${photos.length}\` photo(s).`);
return photos;
},
};
81 changes: 81 additions & 0 deletions components/unsplash/common/constants.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
const BASE_URL = "https://api.unsplash.com";
const API_VERSION = "v1";
const DEFAULT_MAX = 100;
const DEFAULT_LIMIT = 100;

const CONTENT_FILTERS = [
"low",
"high",
];

const COLOR_OPTIONS = [
{
label: "Black and White",
value: "black_and_white",
},
{
label: "Black",
value: "black",
},
{
label: "White",
value: "white",
},
{
label: "Yellow",
value: "yellow",
},
{
label: "Orange",
value: "orange",
},
{
label: "Red",
value: "red",
},
{
label: "Purple",
value: "purple",
},
{
label: "Magenta",
value: "magenta",
},
{
label: "Green",
value: "green",
},
{
label: "Teal",
value: "teal",
},
{
label: "Blue",
value: "blue",
},
];

const ORIENTATION_OPTIONS = [
{
label: "Landscape",
value: "landscape",
},
{
label: "Portrait",
value: "portrait",
},
{
label: "Squarish",
value: "squarish",
},
];

export default {
BASE_URL,
API_VERSION,
DEFAULT_LIMIT,
DEFAULT_MAX,
CONTENT_FILTERS,
COLOR_OPTIONS,
ORIENTATION_OPTIONS,
};
34 changes: 34 additions & 0 deletions components/unsplash/common/utils.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
function parseLinkHeader(linkHeader) {
return linkHeader?.split(",")
.reduce((props, link) => {
const [
url,
rel,
] = link.split(";");
const [
, value,
] = url.split("<");
const [
, key,
] = rel.split("=");
const clearKey = key.replace(/"/g, "");
const clearValue = value.replace(/>/g, "");
return {
...props,
[clearKey]: clearValue,
};
}, {});
}

async function iterate(iterations) {
const items = [];
for await (const item of iterations) {
items.push(item);
}
return items;
}

export default {
iterate,
parseLinkHeader,
};
18 changes: 18 additions & 0 deletions components/unsplash/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "@pipedream/unsplash",
"version": "0.0.1",
"description": "Pipedream Unsplash Components",
"main": "unsplash.app.mjs",
"keywords": [
"pipedream",
"unsplash"
],
"homepage": "https://pipedream.com/apps/unsplash",
"author": "Pipedream <[email protected]> (https://pipedream.com/)",
"publishConfig": {
"access": "public"
},
"dependencies": {
"@pipedream/platform": "^1.6.5"
}
}
95 changes: 91 additions & 4 deletions components/unsplash/unsplash.app.mjs
Original file line number Diff line number Diff line change
@@ -1,11 +1,98 @@
import { axios } from "@pipedream/platform";
import utils from "./common/utils.mjs";
import constants from "./common/constants.mjs";

export default {
type: "app",
app: "unsplash",
propDefinitions: {},
propDefinitions: {
photoId: {
type: "string",
label: "Photo ID",
description: "The ID of the photo to retrieve.",
async options({ page }) {
const photos = await this.listPhotos({
params: {
page: page + 1,
per_page: constants.DEFAULT_LIMIT,
},
});
return photos.map(({
id: value, slug: label,
}) => ({
label,
value,
}));
},
},
},
methods: {
// this.$auth contains connected account data
authKeys() {
console.log(Object.keys(this.$auth));
getUrl(path) {
return `${constants.BASE_URL}${path}`;
},
getHeaders(headers) {
return {
...headers,
"Accept-Version": constants.API_VERSION,
"Authorization": `Bearer ${this.$auth.oauth_access_token}`,
};
},
_makeRequest({
$ = this, path, headers, ...args
} = {}) {
return axios($, {
...args,
debug: true,
url: this.getUrl(path),
headers: this.getHeaders(headers),
});
},
listPhotos(args = {}) {
return this._makeRequest({
path: "/photos",
...args,
});
},
async *getIterations({
resourcesFn, resourcesFnArgs, resourceName,
max = constants.DEFAULT_MAX,
}) {
let page = 1;
let resourcesCount = 0;

while (true) {
const response =
await resourcesFn({
...resourcesFnArgs,
params: {
...resourcesFnArgs?.params,
page,
per_page: constants.DEFAULT_LIMIT,
},
});

const nextResources = resourceName && response[resourceName] || response;

if (!nextResources?.length) {
console.log("No more resources found");
return;
}

for (const resource of nextResources) {
yield resource;
resourcesCount += 1;

if (resourcesCount >= max) {
console.log("Reached max resources");
return;
}
}

page += 1;
}
},
paginate(args = {}) {
return utils.iterate(this.getIterations(args));
},
},
};
6 changes: 6 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 473f97d

Please sign in to comment.