Skip to content

Commit

Permalink
Implement issue creation subscription
Browse files Browse the repository at this point in the history
In this update, a subscription for issue creation has been implemented, enabling real-time updates when an issue is created. This includes changes in the resolvers on the backend and updating some related GraphQL queries on the frontend. The dependencies were also updated to support this feature, with packages including "@graphql-tools/schema", "graphql-postgres-subscriptions", and "graphql-ws" added to backend and the "graphql-ws" version updated on the frontend.
  • Loading branch information
claygorman committed Dec 31, 2023
1 parent 5fb8f2f commit 26f5f86
Show file tree
Hide file tree
Showing 14 changed files with 279 additions and 44 deletions.
4 changes: 4 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,18 @@
"@fastify/cors": "^8.4.1",
"@fastify/websocket": "^8.3.0",
"@graphql-tools/merge": "^9.0.1",
"@graphql-tools/schema": "^10.0.2",
"@hocuspocus/extension-database": "^2.8.1",
"@hocuspocus/server": "^2.8.1",
"axios": "^1.6.0",
"fastify": "^4.24.3",
"fastify-graceful-shutdown": "^3.5.1",
"fastify-socket.io": "^5.0.0",
"graphql": "^16.8.1",
"graphql-postgres-subscriptions": "^1.0.5",
"graphql-tag": "^2.12.6",
"graphql-upload": "^16.0.2",
"graphql-ws": "^5.14.3",
"lodash-es": "^4.17.21",
"minio": "^7.1.3",
"pg": "^8.11.3",
Expand All @@ -46,6 +49,7 @@
},
"devDependencies": {
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/ws": "^8.5.10",
"chai": "^4.3.10",
"mocha": "^10.2.0",
"prettier": "^3.0.3",
Expand Down
107 changes: 105 additions & 2 deletions backend/pnpm-lock.yaml

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

17 changes: 15 additions & 2 deletions backend/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { ApolloServer } from '@apollo/server';
import { fastifyApolloDrainPlugin, fastifyApolloHandler } from '@as-integrations/fastify';
import * as cors from '@fastify/cors';
import { fastifyWebsocket } from '@fastify/websocket';
import { makeExecutableSchema } from '@graphql-tools/schema';
import axios from 'axios';
import Fastify from 'fastify';
import fastifyIO from 'fastify-socket.io';
import processRequest from 'graphql-upload/processRequest.mjs';
import { makeHandler } from 'graphql-ws/lib/use/@fastify/websocket';
import { GraphQLError } from 'graphql/error/index.js';

import { db } from './db/index.js';
Expand All @@ -25,6 +27,8 @@ import { minioClient } from './services/minio-client.js';
import { socketInit } from './socket/index.js';
import typeDefs from './type-defs.js';

const schema = makeExecutableSchema({ typeDefs, resolvers });

const fastify = Fastify({
logger: ENABLE_FASTIFY_LOGGING,
keepAliveTimeout: 61 * 1000,
Expand Down Expand Up @@ -114,8 +118,13 @@ const apollo = new ApolloServer({
await apollo.start();

const myContextFunction = async (request) => {
let token = request?.headers?.authorization;

if (request?.connectionParams?.headers?.Authorization) {
token = request?.connectionParams?.headers?.Authorization;
}

// get the user token from the headers
const token = request.headers.authorization;
let user = null;

// Allow if introspection query only
Expand All @@ -131,7 +140,7 @@ const myContextFunction = async (request) => {
try {
// TODO: maybe we just call the url of the caller origin
const { data } = await axios.get(`${FRONTEND_HOSTNAME}/api/verify-jwt`, {
headers: { Authorization: request.headers.authorization },
headers: { Authorization: token },
});

// TODO: We can inject from DB here the whitelist domains and emails in addition to ENV vars
Expand Down Expand Up @@ -208,6 +217,10 @@ const myContextFunction = async (request) => {
};
};

fastify.register(async (fastify) => {
fastify.get('/graphql', { websocket: true }, makeHandler({ schema, context: myContextFunction }));
});

fastify.post(
'/graphql',
fastifyApolloHandler(apollo, {
Expand Down
15 changes: 14 additions & 1 deletion backend/src/resolvers/Issue/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { Op } from 'sequelize';

import pubsub from '../../services/apollo-pg-pubsub.js';

const resolvers = {
Subscription: {
issueCreated: {
subscribe: () => pubsub.asyncIterator(['ISSUE_CREATED']),
},
},
Query: {
issues: (parent, { input: { projectId, id, search, searchOperator } }, { db }) => {
let whereOr = [];
Expand Down Expand Up @@ -175,7 +182,13 @@ const resolvers = {

const issueStatus = await db.sequelize.models.IssueStatuses.findByPk(issueStatusId);

return { ...issue.toJSON(), status: issueStatus.toJSON() };
const returnData = { ...issue.toJSON(), status: issueStatus.toJSON() };

pubsub.publish('ISSUE_CREATED', {
issueCreated: returnData,
});

return returnData;
},
deleteIssue: async (parent, { input }, { db }) => {
const { id } = input;
Expand Down
14 changes: 14 additions & 0 deletions backend/src/services/apollo-pg-pubsub.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { PostgresPubSub } from 'graphql-postgres-subscriptions';
import pkg from 'pg';

import { SQL_URI } from './config.js';

const { Client } = pkg;

const client = new Client({
connectionString: SQL_URI,
});
await client.connect();
const pubsub = new PostgresPubSub({ client });

export default pubsub;
5 changes: 5 additions & 0 deletions backend/src/type-defs.js
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,11 @@ const typeDefs = gql`
issues(input: QueryIssueInput): [Issue]
issue(input: QueryIssueInput): Issue
}
# SUBSCRIPTIONS
type Subscription {
issueCreated: Issue
}
`;

export default typeDefs;
17 changes: 14 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,17 @@ services:

frontend:
container_name: frontend
image: ghcr.io/openpro-io/openpro-frontend:latest
build:
context: ./frontend
dockerfile: ./Dockerfile
args:
DOCKER_BUILDKIT: 1
environment:
NEXT_PUBLIC_API_URL: http://backend:8080
NEXT_PUBLIC_DEFAULT_LOGIN_PROVIDER: keycloak
NEXTAUTH_URL: http://localhost:3000
NEXTAUTH_SECRET: # openssl rand -base64 32
NEXTAUTH_SECRET: 68a8450a7e7945f6a0c83cef2d46eae177564ac7c6c3872f55bdb04f36f568be
NEXT_PUBLIC_NEXTAUTH_URL: http://localhost:3000
NEXT_PUBLIC_DEFAULT_LOGIN_PROVIDER: # github|keycloak

# Uncomment the following lines to enable keycloak OAuth
#AUTH_KEYCLOAK_ID:
Expand All @@ -95,6 +99,13 @@ services:
# Uncomment the following lines to enable GitHub OAuth
#GITHUB_CLIENT_ID: <client-id>
#GITHUB_CLIENT_SECRET: <client-secret>
AUTH_KEYCLOAK_ID: scrumboard
AUTH_KEYCLOAK_SECRET: H4yFPBaVBgsYmcwsghEVuEgOXcEkX0YU
AUTH_KEYCLOAK_ISSUER: https://auth.oauthd.me/realms/claysjira
KEYCLOAK_BASE_URL: https://auth.oauthd.me
NFTY_WS_HOST: localhost:8093
NFTY_WS_SSL: false
PUBLIC_NFTY_HTTP_SSL: false
networks:
- internal
ports:
Expand Down
Loading

0 comments on commit 26f5f86

Please sign in to comment.