From 71d6a57cdc635756564cc58fc73c57221429775c Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Fri, 21 Oct 2022 01:33:40 +0200 Subject: [PATCH] feat(flickr): add authentication --- .../src/apps/flickr/auth/create-auth-data.ts | 31 ++ .../backend/src/apps/flickr/auth/index.ts | 221 +++++++++++++ .../src/apps/flickr/auth/is-still-verified.ts | 17 + .../apps/flickr/auth/verify-credentials.ts | 26 ++ .../backend/src/apps/flickr/authentication.ts | 82 ----- .../src/apps/flickr/common/add-auth-header.ts | 41 +++ .../src/apps/flickr/common/oauth-client.ts | 23 ++ packages/backend/src/apps/flickr/data.ts | 10 - .../src/apps/flickr/data/list-albums.ts | 39 --- packages/backend/src/apps/flickr/index.d.ts | 1 - packages/backend/src/apps/flickr/index.ts | 38 +-- packages/backend/src/apps/flickr/info.json | 304 ------------------ packages/backend/src/apps/flickr/triggers.ts | 19 -- .../src/apps/flickr/triggers/new-album.ts | 103 ------ .../flickr/triggers/new-favorite-photo.ts | 62 ---- .../flickr/triggers/new-photo-in-album.ts | 80 ----- .../src/apps/flickr/triggers/new-photo.ts | 88 ----- packages/backend/src/models/app.ts | 8 +- packages/backend/tsconfig.json | 1 - 19 files changed, 380 insertions(+), 814 deletions(-) create mode 100644 packages/backend/src/apps/flickr/auth/create-auth-data.ts create mode 100644 packages/backend/src/apps/flickr/auth/index.ts create mode 100644 packages/backend/src/apps/flickr/auth/is-still-verified.ts create mode 100644 packages/backend/src/apps/flickr/auth/verify-credentials.ts delete mode 100644 packages/backend/src/apps/flickr/authentication.ts create mode 100644 packages/backend/src/apps/flickr/common/add-auth-header.ts create mode 100644 packages/backend/src/apps/flickr/common/oauth-client.ts delete mode 100644 packages/backend/src/apps/flickr/data.ts delete mode 100644 packages/backend/src/apps/flickr/data/list-albums.ts delete mode 100644 packages/backend/src/apps/flickr/info.json delete mode 100644 packages/backend/src/apps/flickr/triggers.ts delete mode 100644 packages/backend/src/apps/flickr/triggers/new-album.ts delete mode 100644 packages/backend/src/apps/flickr/triggers/new-favorite-photo.ts delete mode 100644 packages/backend/src/apps/flickr/triggers/new-photo-in-album.ts delete mode 100644 packages/backend/src/apps/flickr/triggers/new-photo.ts diff --git a/packages/backend/src/apps/flickr/auth/create-auth-data.ts b/packages/backend/src/apps/flickr/auth/create-auth-data.ts new file mode 100644 index 00000000..54e7a200 --- /dev/null +++ b/packages/backend/src/apps/flickr/auth/create-auth-data.ts @@ -0,0 +1,31 @@ +import { IJSONObject, IField, IGlobalVariable } from '@automatisch/types'; +import { URLSearchParams } from 'url'; + +export default async function createAuthData($: IGlobalVariable) { + try { + const oauthRedirectUrlField = $.app.auth.fields.find( + (field: IField) => field.key == 'oAuthRedirectUrl' + ); + + const callbackUrl = oauthRedirectUrlField.value; + const requestPath = '/oauth/request_token'; + const data = { oauth_callback: callbackUrl }; + + const response = await $.http.post(requestPath, data); + const responseData = Object.fromEntries(new URLSearchParams(response.data)); + + await $.auth.set({ + url: `${$.app.apiBaseUrl}/oauth/authorize?oauth_token=${responseData.oauth_token}&perms=delete`, + accessToken: responseData.oauth_token, + accessSecret: responseData.oauth_token_secret, + }); + } catch (error) { + const errorMessages = error.response.data.errors + .map((error: IJSONObject) => error.message) + .join(' '); + + throw new Error( + `Error occured while verifying credentials: ${errorMessages}` + ); + } +} diff --git a/packages/backend/src/apps/flickr/auth/index.ts b/packages/backend/src/apps/flickr/auth/index.ts new file mode 100644 index 00000000..6f0e4d0e --- /dev/null +++ b/packages/backend/src/apps/flickr/auth/index.ts @@ -0,0 +1,221 @@ +import createAuthData from './create-auth-data'; +import verifyCredentials from './verify-credentials'; +import isStillVerified from './is-still-verified'; + +export default { + fields: [ + { + key: 'oAuthRedirectUrl', + label: 'OAuth Redirect URL', + type: 'string', + required: true, + readOnly: true, + value: '{WEB_APP_URL}/app/flickr/connections/add', + placeholder: null, + description: 'When asked to input an OAuth callback or redirect URL in Flickr OAuth, enter the URL above.', + docUrl: 'https://automatisch.io/docs/flickr#oauth-redirect-url', + clickToCopy: true + }, + { + key: 'consumerKey', + label: 'Consumer Key', + type: 'string', + required: true, + readOnly: false, + value: null, + placeholder: null, + description: null, + docUrl: 'https://automatisch.io/docs/flickr#consumer-key', + clickToCopy: false + }, + { + key: 'consumerSecret', + label: 'Consumer Secret', + type: 'string', + required: true, + readOnly: false, + value: null, + placeholder: null, + description: null, + docUrl: 'https://automatisch.io/docs/flickr#consumer-secret', + clickToCopy: false + } + ], + authenticationSteps: [ + { + step: 1, + type: 'mutation', + name: 'createConnection', + arguments: [ + { + name: 'key', + value: '{key}' + }, + { + name: 'formattedData', + value: null, + properties: [ + { + name: 'consumerKey', + value: '{fields.consumerKey}' + }, + { + name: 'consumerSecret', + value: '{fields.consumerSecret}' + } + ] + } + ] + }, + { + step: 2, + type: 'mutation', + name: 'createAuthData', + arguments: [ + { + name: 'id', + value: '{createConnection.id}' + } + ] + }, + { + step: 3, + type: 'openWithPopup', + name: 'openAuthPopup', + arguments: [ + { + name: 'url', + value: '{createAuthData.url}' + } + ] + }, + { + step: 4, + type: 'mutation', + name: 'updateConnection', + arguments: [ + { + name: 'id', + value: '{createConnection.id}' + }, + { + name: 'formattedData', + value: null, + properties: [ + { + name: 'oauthVerifier', + value: '{openAuthPopup.oauth_verifier}' + } + ] + } + ] + }, + { + step: 5, + type: 'mutation', + name: 'verifyConnection', + arguments: [ + { + name: 'id', + value: '{createConnection.id}' + } + ] + } + ], + reconnectionSteps: [ + { + step: 1, + type: 'mutation', + name: 'resetConnection', + arguments: [ + { + name: 'id', + value: '{connection.id}' + } + ] + }, + { + step: 2, + type: 'mutation', + name: 'updateConnection', + arguments: [ + { + name: 'id', + value: '{connection.id}' + }, + { + name: 'formattedData', + value: null, + properties: [ + { + name: 'consumerKey', + value: '{fields.consumerKey}' + }, + { + name: 'consumerSecret', + value: '{fields.consumerSecret}' + } + ] + } + ] + }, + { + step: 3, + type: 'mutation', + name: 'createAuthData', + arguments: [ + { + name: 'id', + value: '{connection.id}' + } + ] + }, + { + step: 4, + type: 'openWithPopup', + name: 'openAuthPopup', + arguments: [ + { + name: 'url', + value: '{createAuthData.url}' + } + ] + }, + { + step: 5, + type: 'mutation', + name: 'updateConnection', + arguments: [ + { + name: 'id', + value: '{connection.id}' + }, + { + name: 'formattedData', + value: null, + properties: [ + { + name: 'oauthVerifier', + value: '{openAuthPopup.oauth_verifier}' + } + ] + } + ] + }, + { + step: 6, + type: 'mutation', + name: 'verifyConnection', + arguments: [ + { + name: 'id', + value: '{connection.id}' + } + ] + } + ], + + createAuthData, + verifyCredentials, + isStillVerified, +}; diff --git a/packages/backend/src/apps/flickr/auth/is-still-verified.ts b/packages/backend/src/apps/flickr/auth/is-still-verified.ts new file mode 100644 index 00000000..2d70bce1 --- /dev/null +++ b/packages/backend/src/apps/flickr/auth/is-still-verified.ts @@ -0,0 +1,17 @@ +import { IGlobalVariable } from '@automatisch/types'; + +const isStillVerified = async ($: IGlobalVariable) => { + try { + const params = { + method: 'flickr.test.login', + format: 'json', + nojsoncallback: 1, + } + const response = await $.http.get('/rest', { params }); + return !!response.data.user.id; + } catch (error) { + return false; + } +}; + +export default isStillVerified; diff --git a/packages/backend/src/apps/flickr/auth/verify-credentials.ts b/packages/backend/src/apps/flickr/auth/verify-credentials.ts new file mode 100644 index 00000000..160ada6e --- /dev/null +++ b/packages/backend/src/apps/flickr/auth/verify-credentials.ts @@ -0,0 +1,26 @@ +import { IGlobalVariable } from '@automatisch/types'; +import { URLSearchParams } from 'url'; + +const verifyCredentials = async ($: IGlobalVariable) => { + try { + const response = await $.http.post( + `/oauth/access_token?oauth_verifier=${$.auth.data.oauthVerifier}&oauth_token=${$.auth.data.accessToken}`, + null + ); + + const responseData = Object.fromEntries(new URLSearchParams(response.data)); + + await $.auth.set({ + consumerKey: $.auth.data.consumerKey, + consumerSecret: $.auth.data.consumerSecret, + accessToken: responseData.oauth_token, + accessSecret: responseData.oauth_token_secret, + userId: responseData.user_nsid, + screenName: responseData.fullname, + }); + } catch (error) { + throw new Error(error.response.data); + } +}; + +export default verifyCredentials; diff --git a/packages/backend/src/apps/flickr/authentication.ts b/packages/backend/src/apps/flickr/authentication.ts deleted file mode 100644 index dbb095ac..00000000 --- a/packages/backend/src/apps/flickr/authentication.ts +++ /dev/null @@ -1,82 +0,0 @@ -import type { - IAuthentication, - IApp, - IField, - IJSONObject, -} from '@automatisch/types'; -import FlickrApi from 'flickr-sdk'; - -export default class Authentication implements IAuthentication { - appData: IApp; - connectionData: IJSONObject; - client: typeof FlickrApi; - oauthClient: typeof FlickrApi; - - constructor(appData: IApp, connectionData: IJSONObject) { - this.oauthClient = new FlickrApi.OAuth( - connectionData.consumerKey, - connectionData.consumerSecret - ); - - if (connectionData.accessToken && connectionData.accessSecret) { - this.client = new FlickrApi( - FlickrApi.OAuth.createPlugin( - connectionData.consumerKey, - connectionData.consumerSecret, - connectionData.accessToken, - connectionData.accessSecret - ) - ); - } - - this.connectionData = connectionData; - this.appData = appData; - } - - async createAuthData() { - const appFields = this.appData.fields.find( - (field: IField) => field.key == 'oAuthRedirectUrl' - ); - const callbackUrl = appFields.value; - - const oauthData = (await this.oauthClient.request(callbackUrl)).body; - const url = await this.oauthClient.authorizeUrl( - oauthData.oauth_token, - 'delete' - ); - - return { - accessToken: oauthData.oauth_token, - accessSecret: oauthData.oauth_token_secret, - url: url, - }; - } - - async verifyCredentials() { - const verifiedCredentials = ( - await this.oauthClient.verify( - this.connectionData.accessToken, - this.connectionData.oauthVerifier, - this.connectionData.accessSecret - ) - ).body; - - return { - consumerKey: this.connectionData.consumerKey, - consumerSecret: this.connectionData.consumerSecret, - accessToken: verifiedCredentials.oauth_token, - accessSecret: verifiedCredentials.oauth_token_secret, - userId: verifiedCredentials.user_nsid, - screenName: verifiedCredentials.fullname, - }; - } - - async isStillVerified() { - try { - await this.client.test.login(); - return true; - } catch { - return false; - } - } -} diff --git a/packages/backend/src/apps/flickr/common/add-auth-header.ts b/packages/backend/src/apps/flickr/common/add-auth-header.ts new file mode 100644 index 00000000..7e9daa02 --- /dev/null +++ b/packages/backend/src/apps/flickr/common/add-auth-header.ts @@ -0,0 +1,41 @@ +import { Token } from 'oauth-1.0a'; +import { IJSONObject, TBeforeRequest } from '@automatisch/types'; +import oauthClient from './oauth-client'; + +type RequestDataType = { + url: string; + method: string; + data?: IJSONObject; +}; + +const addAuthHeader: TBeforeRequest = ($, requestConfig) => { + const { url, method, data, params } = requestConfig; + + const token: Token = { + key: $.auth.data?.accessToken as string, + secret: $.auth.data?.accessSecret as string, + }; + + const requestData: RequestDataType = { + url: `${requestConfig.baseURL}${url}`, + method, + }; + + if (url === '/oauth/request_token') { + requestData.data = data; + } + + if (method === 'get') { + requestData.data = params; + } + + const authHeader = oauthClient($).toHeader( + oauthClient($).authorize(requestData, token) + ); + + requestConfig.headers.Authorization = authHeader.Authorization; + + return requestConfig; +}; + +export default addAuthHeader; diff --git a/packages/backend/src/apps/flickr/common/oauth-client.ts b/packages/backend/src/apps/flickr/common/oauth-client.ts new file mode 100644 index 00000000..c29f6a0a --- /dev/null +++ b/packages/backend/src/apps/flickr/common/oauth-client.ts @@ -0,0 +1,23 @@ +import { IGlobalVariable } from '@automatisch/types'; +import crypto from 'crypto'; +import OAuth from 'oauth-1.0a'; + +const oauthClient = ($: IGlobalVariable) => { + const consumerData = { + key: $.auth.data.consumerKey as string, + secret: $.auth.data.consumerSecret as string, + }; + + return new OAuth({ + consumer: consumerData, + signature_method: 'HMAC-SHA1', + hash_function(base_string, key) { + return crypto + .createHmac('sha1', key) + .update(base_string) + .digest('base64'); + }, + }); +}; + +export default oauthClient; diff --git a/packages/backend/src/apps/flickr/data.ts b/packages/backend/src/apps/flickr/data.ts deleted file mode 100644 index c9fad235..00000000 --- a/packages/backend/src/apps/flickr/data.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { IJSONObject } from '@automatisch/types'; -import ListAlbums from './data/list-albums'; - -export default class Data { - listAlbums: ListAlbums; - - constructor(connectionData: IJSONObject) { - this.listAlbums = new ListAlbums(connectionData); - } -} diff --git a/packages/backend/src/apps/flickr/data/list-albums.ts b/packages/backend/src/apps/flickr/data/list-albums.ts deleted file mode 100644 index 83714ff6..00000000 --- a/packages/backend/src/apps/flickr/data/list-albums.ts +++ /dev/null @@ -1,39 +0,0 @@ -import FlickrApi from 'flickr-sdk'; -import type { IJSONObject } from '@automatisch/types'; - -export default class ListAlbums { - client?: typeof FlickrApi; - - constructor(connectionData: IJSONObject) { - if ( - connectionData.consumerKey && - connectionData.consumerSecret && - connectionData.accessToken && - connectionData.accessSecret - ) { - this.client = new FlickrApi( - FlickrApi.OAuth.createPlugin( - connectionData.consumerKey, - connectionData.consumerSecret, - connectionData.accessToken, - connectionData.accessSecret - ) - ); - } - } - - async run() { - const { photosets } = (await this.client.photosets.getList()).body; - const allPhotosets = [...photosets.photoset]; - - for (let page = photosets.page + 1; page <= photosets.pages; page++) { - const { photosets } = (await this.client.photosets.getList({ page, })).body; - allPhotosets.push(...photosets.photoset); - } - - return allPhotosets.map((photoset) => ({ - value: photoset.id, - name: photoset.title._content, - })); - } -} diff --git a/packages/backend/src/apps/flickr/index.d.ts b/packages/backend/src/apps/flickr/index.d.ts index 1a21c85c..e69de29b 100644 --- a/packages/backend/src/apps/flickr/index.d.ts +++ b/packages/backend/src/apps/flickr/index.d.ts @@ -1 +0,0 @@ -declare module 'flickr-sdk'; diff --git a/packages/backend/src/apps/flickr/index.ts b/packages/backend/src/apps/flickr/index.ts index 5a5ca222..ca71f2af 100644 --- a/packages/backend/src/apps/flickr/index.ts +++ b/packages/backend/src/apps/flickr/index.ts @@ -1,25 +1,15 @@ -import { - IService, - IAuthentication, - IApp, - IJSONObject, -} from '@automatisch/types'; -import Authentication from './authentication'; -import Triggers from './triggers'; -import Data from './data'; +import defineApp from '../../helpers/define-app'; +import addAuthHeader from './common/add-auth-header'; -export default class Flickr implements IService { - authenticationClient: IAuthentication; - triggers: Triggers; - data: Data; - - constructor( - appData: IApp, - connectionData: IJSONObject, - parameters: IJSONObject - ) { - this.authenticationClient = new Authentication(appData, connectionData); - this.data = new Data(connectionData); - this.triggers = new Triggers(connectionData, parameters); - } -} +export default defineApp({ + name: 'Flickr', + key: 'flickr', + iconUrl: '{BASE_URL}/apps/flickr/assets/favicon.svg', + authDocUrl: 'https://automatisch.io/docs/connections/flickr', + docUrl: 'https://automatisch.io/docs/flickr', + primaryColor: '000000', + supportsConnections: true, + baseUrl: 'https://www.flickr.com/', + apiBaseUrl: 'https://www.flickr.com/services', + beforeRequest: [addAuthHeader], +}); diff --git a/packages/backend/src/apps/flickr/info.json b/packages/backend/src/apps/flickr/info.json deleted file mode 100644 index 3d1e6329..00000000 --- a/packages/backend/src/apps/flickr/info.json +++ /dev/null @@ -1,304 +0,0 @@ -{ - "name": "Flickr", - "key": "flickr", - "iconUrl": "{BASE_URL}/apps/flickr/assets/favicon.svg", - "docUrl": "https://automatisch.io/docs/flickr", - "primaryColor": "000000", - "supportsConnections": true, - "fields": [ - { - "key": "oAuthRedirectUrl", - "label": "OAuth Redirect URL", - "type": "string", - "required": true, - "readOnly": true, - "value": "{WEB_APP_URL}/app/flickr/connections/add", - "placeholder": null, - "description": "When asked to input an OAuth callback or redirect URL in Flickr OAuth, enter the URL above.", - "docUrl": "https://automatisch.io/docs/flickr#oauth-redirect-url", - "clickToCopy": true - }, - { - "key": "consumerKey", - "label": "Consumer Key", - "type": "string", - "required": true, - "readOnly": false, - "value": null, - "placeholder": null, - "description": null, - "docUrl": "https://automatisch.io/docs/flickr#consumer-key", - "clickToCopy": false - }, - { - "key": "consumerSecret", - "label": "Consumer Secret", - "type": "string", - "required": true, - "readOnly": false, - "value": null, - "placeholder": null, - "description": null, - "docUrl": "https://automatisch.io/docs/flickr#consumer-secret", - "clickToCopy": false - } - ], - "authenticationSteps": [ - { - "step": 1, - "type": "mutation", - "name": "createConnection", - "arguments": [ - { - "name": "key", - "value": "{key}" - }, - { - "name": "formattedData", - "value": null, - "properties": [ - { - "name": "consumerKey", - "value": "{fields.consumerKey}" - }, - { - "name": "consumerSecret", - "value": "{fields.consumerSecret}" - } - ] - } - ] - }, - { - "step": 2, - "type": "mutation", - "name": "createAuthData", - "arguments": [ - { - "name": "id", - "value": "{createConnection.id}" - } - ] - }, - { - "step": 3, - "type": "openWithPopup", - "name": "openAuthPopup", - "arguments": [ - { - "name": "url", - "value": "{createAuthData.url}" - } - ] - }, - { - "step": 4, - "type": "mutation", - "name": "updateConnection", - "arguments": [ - { - "name": "id", - "value": "{createConnection.id}" - }, - { - "name": "formattedData", - "value": null, - "properties": [ - { - "name": "oauthVerifier", - "value": "{openAuthPopup.oauth_verifier}" - } - ] - } - ] - }, - { - "step": 5, - "type": "mutation", - "name": "verifyConnection", - "arguments": [ - { - "name": "id", - "value": "{createConnection.id}" - } - ] - } - ], - "reconnectionSteps": [ - { - "step": 1, - "type": "mutation", - "name": "resetConnection", - "arguments": [ - { - "name": "id", - "value": "{connection.id}" - } - ] - }, - { - "step": 2, - "type": "mutation", - "name": "updateConnection", - "arguments": [ - { - "name": "id", - "value": "{connection.id}" - }, - { - "name": "formattedData", - "value": null, - "properties": [ - { - "name": "consumerKey", - "value": "{fields.consumerKey}" - }, - { - "name": "consumerSecret", - "value": "{fields.consumerSecret}" - } - ] - } - ] - }, - { - "step": 3, - "type": "mutation", - "name": "createAuthData", - "arguments": [ - { - "name": "id", - "value": "{connection.id}" - } - ] - }, - { - "step": 4, - "type": "openWithPopup", - "name": "openAuthPopup", - "arguments": [ - { - "name": "url", - "value": "{createAuthData.url}" - } - ] - }, - { - "step": 5, - "type": "mutation", - "name": "updateConnection", - "arguments": [ - { - "name": "id", - "value": "{connection.id}" - }, - { - "name": "formattedData", - "value": null, - "properties": [ - { - "name": "oauthVerifier", - "value": "{openAuthPopup.oauth_verifier}" - } - ] - } - ] - }, - { - "step": 6, - "type": "mutation", - "name": "verifyConnection", - "arguments": [ - { - "name": "id", - "value": "{connection.id}" - } - ] - } - ], - "triggers": [ - { - "name": "New favorite photo", - "key": "newFavoritePhoto", - "description": "Triggers when you favorite a photo.", - "substeps": [ - { - "key": "chooseConnection", - "name": "Choose connection" - }, - { - "key": "testStep", - "name": "Test trigger" - } - ] - }, - { - "name": "New photo in album", - "key": "newPhotoInAlbum", - "description": "Triggers when you add a new photo in an album.", - "substeps": [ - { - "key": "chooseConnection", - "name": "Choose connection" - }, - { - "key": "chooseTrigger", - "name": "Set up a trigger", - "arguments": [ - { - "label": "Album", - "key": "album", - "type": "dropdown", - "required": true, - "variables": false, - "source": { - "type": "query", - "name": "getData", - "arguments": [ - { - "name": "key", - "value": "listAlbums" - } - ] - } - } - ] - }, - { - "key": "testStep", - "name": "Test trigger" - } - ] - }, - { - "name": "New photo", - "key": "newPhoto", - "description": "Triggers when you add a new photo.", - "substeps": [ - { - "key": "chooseConnection", - "name": "Choose connection" - }, - { - "key": "testStep", - "name": "Test trigger" - } - ] - }, - { - "name": "New album", - "key": "newAlbum", - "description": "Triggers when you create a new album.", - "substeps": [ - { - "key": "chooseConnection", - "name": "Choose connection" - }, - { - "key": "testStep", - "name": "Test trigger" - } - ] - } - ] -} diff --git a/packages/backend/src/apps/flickr/triggers.ts b/packages/backend/src/apps/flickr/triggers.ts deleted file mode 100644 index 5ffabd8c..00000000 --- a/packages/backend/src/apps/flickr/triggers.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { IJSONObject } from '@automatisch/types'; -import NewFavoritePhoto from './triggers/new-favorite-photo'; -import NewPhotoInAlbum from './triggers/new-photo-in-album'; -import NewPhoto from './triggers/new-photo'; -import NewAlbum from './triggers/new-album'; - -export default class Triggers { - newFavoritePhoto: NewFavoritePhoto; - newPhotoInAlbum: NewPhotoInAlbum; - newPhoto: NewPhoto; - newAlbum: NewAlbum; - - constructor(connectionData: IJSONObject, parameters: IJSONObject) { - this.newFavoritePhoto = new NewFavoritePhoto(connectionData); - this.newPhotoInAlbum = new NewPhotoInAlbum(connectionData, parameters); - this.newPhoto = new NewPhoto(connectionData); - this.newAlbum = new NewAlbum(connectionData); - } -} diff --git a/packages/backend/src/apps/flickr/triggers/new-album.ts b/packages/backend/src/apps/flickr/triggers/new-album.ts deleted file mode 100644 index 59af7352..00000000 --- a/packages/backend/src/apps/flickr/triggers/new-album.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { DateTime } from 'luxon'; -import FlickrApi from 'flickr-sdk'; -import { IJSONObject } from '@automatisch/types'; - -export default class NewAlbum { - client?: typeof FlickrApi; - connectionData?: IJSONObject; - primaryPhotoExtraFields = [ - 'description', - 'license', - 'date_upload', - 'date_taken', - 'owner_name', - 'icon_server', - 'original_format', - 'last_update', - 'geo', - 'tags', - 'machine_tags', - 'o_dims', - 'views', - 'media', - 'path_alias', - 'url_sq', - 'url_t', - 'url_s', - 'url_q', - 'url_m', - 'url_n', - 'url_z', - 'url_c', - 'url_l', - 'url_o', - ].join(','); - - constructor(connectionData: IJSONObject) { - if ( - connectionData.consumerKey && - connectionData.consumerSecret && - connectionData.accessToken && - connectionData.accessSecret - ) { - this.client = new FlickrApi( - FlickrApi.OAuth.createPlugin( - connectionData.consumerKey, - connectionData.consumerSecret, - connectionData.accessToken, - connectionData.accessSecret - ) - ); - - this.connectionData = connectionData; - } - } - - async getAlbums(options: { perPage?: number, page?: number } = {}) { - const { perPage, page } = options; - const payload = { - page, - per_page: perPage, - primary_photo_extras: this.primaryPhotoExtraFields, - }; - const { photosets } = (await this.client.photosets.getList(payload)).body; - - return photosets; - } - - async run(startTime: Date) { - const albums = await this.getAlbums({ page: 1 }); - const allAlbums = [...albums.photoset]; - const newAlbums = []; - - let page = 1; - for (const album of allAlbums) { - const createdAtInSeconds = DateTime.fromSeconds(parseInt(album.date_create, 10)); - const createdAt = createdAtInSeconds.toMillis(); - - if (createdAt <= startTime.getTime()) { - break; - } - - newAlbums.push(album); - - const currentIndex = allAlbums.indexOf(album); - const totalAlbums = allAlbums.length; - const isLastItem = currentIndex + 1 === totalAlbums; - - if (isLastItem && page < albums.pages) { - page = page + 1; - const { photoset } = await this.getAlbums({ page, }); - allAlbums.push(...photoset.photoset); - } - } - - return newAlbums; - } - - async testRun() { - const { photoset } = await this.getAlbums({ perPage: 1 }); - - return photoset; - } -} diff --git a/packages/backend/src/apps/flickr/triggers/new-favorite-photo.ts b/packages/backend/src/apps/flickr/triggers/new-favorite-photo.ts deleted file mode 100644 index acf9ed6b..00000000 --- a/packages/backend/src/apps/flickr/triggers/new-favorite-photo.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { DateTime } from 'luxon'; -import FlickrApi from 'flickr-sdk'; -import { IJSONObject } from '@automatisch/types'; - -export default class NewFavoritePhoto { - client?: typeof FlickrApi; - - constructor(connectionData: IJSONObject) { - if ( - connectionData.consumerKey && - connectionData.consumerSecret && - connectionData.accessToken && - connectionData.accessSecret - ) { - this.client = new FlickrApi( - FlickrApi.OAuth.createPlugin( - connectionData.consumerKey, - connectionData.consumerSecret, - connectionData.accessToken, - connectionData.accessSecret - ) - ); - } - } - - async run(startTime: Date) { - const { photos } = (await this.client.favorites.getList()).body; - const favPhotos = [...photos.photo]; - const newFavPhotos = []; - - let page = 1; - for (const photo of favPhotos) { - const markedFavoriteAt = DateTime.fromSeconds(parseInt(photo.date_faved, 10)); - const markedFavoriteAtInMillis = markedFavoriteAt.toMillis(); - - if (markedFavoriteAtInMillis <= startTime.getTime()) { - break; - } - - newFavPhotos.push(photo); - - const currentIndex = favPhotos.indexOf(photo); - const totalFavPhotos = favPhotos.length; - const isLastItem = currentIndex + 1 === totalFavPhotos; - - if (isLastItem && page < photos.pages) { - page = page + 1; - const { photos } = (await this.client.favorites.getList({ page, })).body; - favPhotos.push(...photos.photo); - } - } - - return newFavPhotos; - } - - async testRun() { - const { photos } = (await this.client.favorites.getList({ per_page: 1, })).body; - - return photos.photo; - } -} - diff --git a/packages/backend/src/apps/flickr/triggers/new-photo-in-album.ts b/packages/backend/src/apps/flickr/triggers/new-photo-in-album.ts deleted file mode 100644 index 01f90659..00000000 --- a/packages/backend/src/apps/flickr/triggers/new-photo-in-album.ts +++ /dev/null @@ -1,80 +0,0 @@ -import FlickrApi from 'flickr-sdk'; -import { IJSONObject } from '@automatisch/types'; - -export default class NewPhotoInAlbum { - client?: typeof FlickrApi; - connectionData?: IJSONObject; - albumId?: string; - extraFields = [ - 'license', - 'date_upload', - 'date_taken', - 'owner_name', - 'icon_server', - 'original_format', - 'last_update', - 'geo', - 'tags', - 'machine_tags', - 'o_dims', - 'views', - 'media', - 'path_alias', - 'url_sq', - 'url_t', - 'url_s', - 'url_m', - 'url_o' - ].join(','); - - constructor(connectionData: IJSONObject, parameters: IJSONObject) { - if ( - connectionData.consumerKey && - connectionData.consumerSecret && - connectionData.accessToken && - connectionData.accessSecret - ) { - this.client = new FlickrApi( - FlickrApi.OAuth.createPlugin( - connectionData.consumerKey, - connectionData.consumerSecret, - connectionData.accessToken, - connectionData.accessSecret - ) - ); - - this.connectionData = connectionData; - } - - if (parameters?.album) { - this.albumId = parameters.album as string; - } - } - - async getAlbumPhotos(options: { perPage?: number, page?: number } = {}) { - const { perPage, page } = options; - const payload = { - page, - per_page: perPage, - photoset_id: this.albumId, - user_id: this.connectionData.userId, - extras: this.extraFields, - }; - const { photoset } = (await this.client.photosets.getPhotos(payload)).body; - - return photoset; - } - - async run() { - // TODO: implement pagination on undated entries - const { photo } = await this.getAlbumPhotos({ page: 1 }); - - return photo; - } - - async testRun() { - const { photo } = await this.getAlbumPhotos({ perPage: 1 }); - - return photo; - } -} diff --git a/packages/backend/src/apps/flickr/triggers/new-photo.ts b/packages/backend/src/apps/flickr/triggers/new-photo.ts deleted file mode 100644 index de630e6f..00000000 --- a/packages/backend/src/apps/flickr/triggers/new-photo.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { DateTime } from 'luxon'; -import FlickrApi from 'flickr-sdk'; -import { IJSONObject } from '@automatisch/types'; - -export default class NewPhoto { - client?: typeof FlickrApi; - connectionData?: IJSONObject; - extraFields = [ - 'description', - 'license', - 'date_upload', - 'date_taken', - 'owner_name', - 'icon_server', - 'original_format', - 'last_update', - 'geo', - 'tags', - 'machine_tags', - 'o_dims', - 'views', - 'media', - 'path_alias', - 'url_sq', - 'url_t', - 'url_s', - 'url_q', - 'url_m', - 'url_n', - 'url_z', - 'url_c', - 'url_l', - 'url_o', - ].join(','); - - constructor(connectionData: IJSONObject) { - if ( - connectionData.consumerKey && - connectionData.consumerSecret && - connectionData.accessToken && - connectionData.accessSecret - ) { - this.client = new FlickrApi( - FlickrApi.OAuth.createPlugin( - connectionData.consumerKey, - connectionData.consumerSecret, - connectionData.accessToken, - connectionData.accessSecret - ) - ); - - this.connectionData = connectionData; - } - } - - async getPhotos(options: { perPage?: number, page?: number, minUploadDate?: string } = {}) { - const { perPage, page, minUploadDate } = options; - const payload = { - page, - per_page: perPage, - user_id: this.connectionData.userId, - extras: this.extraFields, - min_upload_date: minUploadDate, - }; - const { photos } = (await this.client.photos.search(payload)).body; - - return photos; - } - - async run(startTime: Date) { - const minUploadDate = DateTime.fromJSDate(startTime).toSeconds().toString(); - const photos = await this.getPhotos({ page: 1, minUploadDate }); - const allPhotos = [...photos.photo]; - - for (let page = photos.page + 1; page <= photos.pages; page++) { - const photos = (await this.getPhotos({ page, minUploadDate })); - allPhotos.push(...photos.photo); - } - - return allPhotos; - } - - async testRun(startTime: Date) { - const { photo } = await this.getPhotos({ perPage: 1 }); - - return photo; - } -} diff --git a/packages/backend/src/models/app.ts b/packages/backend/src/models/app.ts index 4fdbf247..958eee1c 100644 --- a/packages/backend/src/models/app.ts +++ b/packages/backend/src/models/app.ts @@ -10,7 +10,13 @@ class App { // Temporaryly restrict the apps we expose until // their actions/triggers are implemented! - static temporaryList = ['github', 'scheduler', 'slack', 'twitter']; + static temporaryList = [ + 'flickr', + 'github', + 'scheduler', + 'slack', + 'twitter', + ]; static async findAll(name?: string, stripFuncs = true): Promise { if (!name) diff --git a/packages/backend/tsconfig.json b/packages/backend/tsconfig.json index a4be27dd..7e68dea0 100644 --- a/packages/backend/tsconfig.json +++ b/packages/backend/tsconfig.json @@ -25,7 +25,6 @@ "exclude": [ "src/apps/discord", "src/apps/firebase", - "src/apps/flickr", "src/apps/gitlab", "src/apps/twitch", "src/apps/typeform"