diff --git a/packages/backend/src/apps/twitch/info.json b/packages/backend/src/apps/twitch/info.json index 809cb523..c2ae4a81 100644 --- a/packages/backend/src/apps/twitch/info.json +++ b/packages/backend/src/apps/twitch/info.json @@ -1,5 +1,6 @@ { "name": "Twitch", + "key": "twitch", "iconUrl": "https://automatisch.io/apps/twitch.png", "docUrl": "https://automatisch.io/docs/twitch", "primaryColor": "6441a5", diff --git a/packages/backend/src/apps/twitter/info.json b/packages/backend/src/apps/twitter/info.json index bdbe385e..47c42c3f 100644 --- a/packages/backend/src/apps/twitter/info.json +++ b/packages/backend/src/apps/twitter/info.json @@ -1,5 +1,6 @@ { "name": "Twitter", + "key": "twitter", "iconUrl": "https://automatisch.io/apps/twitter.png", "docUrl": "https://automatisch.io/docs/twitter", "primaryColor": "2DAAE1", @@ -15,6 +16,17 @@ "docUrl": "https://automatisch.io/docs/twitter#oauth-redirect-url", "clickToCopy": true }, + { + "key": "displayName", + "label": "Name", + "type": "string", + "required": true, + "readOnly": false, + "value": null, + "description": "It's the value you can remember later on while changing connection settings.", + "docUrl": "https://automatisch.io/docs/twitter#display-name", + "clickToCopy": false + }, { "key": "consumerKey", "label": "Consumer Key", @@ -37,5 +49,36 @@ "docUrl": "https://automatisch.io/docs/twitter#consumer-secret", "clickToCopy": false } + ], + "authenticationSteps": [ + { + "step": 1, + "type": "mutation", + "name": "createCredential", + "fields": [ + { + "name": "displayName", + "value": "{fields.displayName}" + }, + { + "name": "key", + "value": "{key}" + }, + { + "name": "data", + "value": "data", + "fields": [ + { + "name": "consumerKey", + "value": "{fields.consumerKey}" + }, + { + "name": "consumerSecret", + "value": "{fields.consumerSecret}" + } + ] + } + ] + } ] } diff --git a/packages/backend/src/db/migrations/20211011120732_create_credentials.ts b/packages/backend/src/db/migrations/20211011120732_create_credentials.ts new file mode 100644 index 00000000..580d2c6d --- /dev/null +++ b/packages/backend/src/db/migrations/20211011120732_create_credentials.ts @@ -0,0 +1,18 @@ +import { Knex } from "knex"; + +export async function up(knex: Knex): Promise { + return knex.schema.createTable('credentials', (table) => { + table.increments('id'); + table.string('key').notNullable(); + table.string('display_name').notNullable(); + table.text('data').notNullable(); + table.integer('user_id').references('id').inTable('users'); + table.boolean('verified').defaultTo(false); + + table.timestamps(true, true); + }); +}; + +export async function down(knex: Knex): Promise { + return knex.schema.dropTable('credentials'); +} diff --git a/packages/backend/src/graphql/graphql-schema.ts b/packages/backend/src/graphql/graphql-schema.ts index fffd590d..182d1393 100644 --- a/packages/backend/src/graphql/graphql-schema.ts +++ b/packages/backend/src/graphql/graphql-schema.ts @@ -1,8 +1,10 @@ import { GraphQLSchema } from 'graphql'; import rootQuery from './root-query'; +import rootMutation from './root-mutation'; const graphQLSchema = new GraphQLSchema({ query: rootQuery, + mutation: rootMutation }); export default graphQLSchema; diff --git a/packages/backend/src/graphql/mutations/create-credential.ts b/packages/backend/src/graphql/mutations/create-credential.ts new file mode 100644 index 00000000..3a99747c --- /dev/null +++ b/packages/backend/src/graphql/mutations/create-credential.ts @@ -0,0 +1,37 @@ +import { GraphQLString, GraphQLNonNull, GraphQLObjectType, GraphQLCompositeType } from 'graphql'; +import Credential from '../../models/credential'; +import credentialType from '../types/credential'; +import twitterCredentialInputType from '../types/twitter-credential-input'; +import User from '../../models/user'; + +type Params = { + key: string, + displayName: string, + data: object +} +const createCredentialResolver = async (params: Params) => { + const user = await User.query().findOne({ + email: 'user@automatisch.com' + }) + + const credential = await Credential.query().insert({ + displayName: params.displayName, + key: params.key, + data: params.data, + userId: user.id + }); + + return credential; +} + +const createCredential = { + type: credentialType, + args: { + key: { type: GraphQLNonNull(GraphQLString) }, + displayName: { type: GraphQLNonNull(GraphQLString) }, + data: { type: GraphQLNonNull(twitterCredentialInputType) } + }, + resolve: (_: any, params: Params) => createCredentialResolver(params) +}; + +export default createCredential; diff --git a/packages/backend/src/graphql/root-mutation.ts b/packages/backend/src/graphql/root-mutation.ts new file mode 100644 index 00000000..1a54013b --- /dev/null +++ b/packages/backend/src/graphql/root-mutation.ts @@ -0,0 +1,11 @@ +import { GraphQLObjectType } from 'graphql'; +import createCredential from './mutations/create-credential'; + +const rootMutation = new GraphQLObjectType({ + name: 'Mutation', + fields: { + createCredential: createCredential + } +}); + +export default rootMutation; diff --git a/packages/backend/src/graphql/types/credential.ts b/packages/backend/src/graphql/types/credential.ts new file mode 100644 index 00000000..6bc3abb2 --- /dev/null +++ b/packages/backend/src/graphql/types/credential.ts @@ -0,0 +1,13 @@ +import { GraphQLObjectType, GraphQLString } from 'graphql'; +import twitterCredentialType from './twitter-credential'; + +const credentialType = new GraphQLObjectType({ + name: 'credential', + fields: { + key: { type: GraphQLString }, + displayName: { type: GraphQLString }, + data: { type: twitterCredentialType }, + } +}) + +export default credentialType; diff --git a/packages/backend/src/graphql/types/twitter-credential-input.ts b/packages/backend/src/graphql/types/twitter-credential-input.ts new file mode 100644 index 00000000..743951bf --- /dev/null +++ b/packages/backend/src/graphql/types/twitter-credential-input.ts @@ -0,0 +1,11 @@ +import { GraphQLString, GraphQLInputObjectType } from 'graphql'; + +const twitterCredentialInputType = new GraphQLInputObjectType({ + name: 'twitterCredentialInput', + fields: { + consumerKey: { type: GraphQLString }, + consumerSecret: { type: GraphQLString }, + } +}) + +export default twitterCredentialInputType; diff --git a/packages/backend/src/graphql/types/twitter-credential.ts b/packages/backend/src/graphql/types/twitter-credential.ts new file mode 100644 index 00000000..9fbad015 --- /dev/null +++ b/packages/backend/src/graphql/types/twitter-credential.ts @@ -0,0 +1,11 @@ +import { GraphQLString, GraphQLObjectType } from 'graphql'; + +const twitterCredentialInputType = new GraphQLObjectType({ + name: 'twitterCredential', + fields: { + consumerKey: { type: GraphQLString }, + consumerSecret: { type: GraphQLString }, + } +}) + +export default twitterCredentialInputType; diff --git a/packages/backend/src/models/credential.ts b/packages/backend/src/models/credential.ts new file mode 100644 index 00000000..3f55904a --- /dev/null +++ b/packages/backend/src/models/credential.ts @@ -0,0 +1,27 @@ +import Base from './base' + +class Credential extends Base { + id!: number + displayName!: string + key!: string + data!: string + userId!: number + + static tableName = 'credentials'; + + static jsonSchema = { + type: 'object', + required: ['displayName', 'key', 'data', 'userId'], + + properties: { + id: { type: 'integer' }, + displayName: { type: 'string', minLength: 1, maxLength: 255 }, + key: { type: 'string', minLength: 1, maxLength: 255 }, + data: { type: 'object' }, + userId: { type: 'integer' }, + verified: { type: 'boolean' }, + } + } +} + +export default Credential;