diff --git a/.github/workflows/build-and-push-docker-image.yml b/.github/workflows/build-and-push-docker-image.yml index 12dd5c6a..c6acacfc 100644 --- a/.github/workflows/build-and-push-docker-image.yml +++ b/.github/workflows/build-and-push-docker-image.yml @@ -3,7 +3,7 @@ name: Build and push docker image on: push: branches: - - '*' + - '**' tags: - 'v*' diff --git a/.github/workflows/bump-version.yml b/.github/workflows/bump-version.yml index 8e03f837..9e495603 100644 --- a/.github/workflows/bump-version.yml +++ b/.github/workflows/bump-version.yml @@ -6,9 +6,11 @@ jobs: # If pull request was merged then we should check for a package version update check-version-update: runs-on: ubuntu-22.04 + outputs: + should-bump: ${{ steps.version-check.outputs.should-bump }} steps: # Checkout to target branch - - uses: actions/checkout@v2 + - uses: actions/checkout@v5 with: fetch-depth: 0 @@ -26,20 +28,29 @@ jobs: id: packageOld uses: codex-team/action-nodejs-package-info@v1 - # Stop workflow and do not bump version if it was changed already - - name: Stop workflow and do not bump version if it was changed already - uses: andymckay/cancel-action@0.2 - if: steps.packageOld.outputs.version != steps.packageNew.outputs.version + # Check if version should be bumped + - name: Check if version should be bumped + id: version-check + run: | + if [ "${{ steps.packageOld.outputs.version }}" == "${{ steps.packageNew.outputs.version }}" ]; then + echo "should-bump=true" >> $GITHUB_OUTPUT + else + echo "should-bump=false" >> $GITHUB_OUTPUT + fi bump-version: needs: check-version-update + if: needs.check-version-update.outputs.should-bump == 'true' runs-on: ubuntu-22.04 steps: # Checkout to target branch - - uses: actions/checkout@v2 + - uses: actions/checkout@v5 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.ref }} # Setup node environment - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v5 with: node-version-file: '.nvmrc' registry-url: https://registry.npmjs.org/ @@ -54,7 +65,7 @@ jobs: uses: codex-team/action-nodejs-package-info@v1 # Commit version upgrade - - uses: EndBug/add-and-commit@v7 + - uses: EndBug/add-and-commit@v9 with: author_name: github-actions author_email: 41898282+github-actions[bot]@users.noreply.github.com diff --git a/package.json b/package.json index 968062e3..96e8a0d9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hawk.api", - "version": "1.1.34", + "version": "1.1.38", "main": "index.ts", "license": "UNLICENSED", "scripts": { diff --git a/src/directives/requireAuth.ts b/src/directives/allowAnon.ts similarity index 61% rename from src/directives/requireAuth.ts rename to src/directives/allowAnon.ts index d5e903a0..7a24cc18 100644 --- a/src/directives/requireAuth.ts +++ b/src/directives/allowAnon.ts @@ -20,37 +20,50 @@ function checkUser(context: ResolverContextBase): void { } } -export default function requireAuthDirective(directiveName = 'requireAuth') { +export default function allowAnonDirective(directiveName = 'allowAnon') { return { - requireAuthDirectiveTypeDefs: ` + allowAnonDirectiveTypeDefs: ` """ - Access to the field only to authorized users + Allow access to the field to anonymous users """ directive @${directiveName} on FIELD_DEFINITION `, - requireAuthDirectiveTransformer: (schema: GraphQLSchema) => + allowAnonDirectiveTransformer: (schema: GraphQLSchema) => mapSchema(schema, { [MapperKind.OBJECT_FIELD]: (fieldConfig, fieldName) => { - const requireAuthDirective = getDirective(schema, fieldConfig, directiveName)?.[0]; + const allowAnonDirective = getDirective(schema, fieldConfig, directiveName)?.[0]; - if (requireAuthDirective) { + if (allowAnonDirective) { + /** Append flag isAnonAllowed to request context */ const { resolve = defaultFieldResolver, } = fieldConfig; - /** - * New field resolver - * @param resolverArgs - default GraphQL resolver args - */ fieldConfig.resolve = async function (...resolverArgs): UnknownGraphQLResolverResult { const [, , context] = resolverArgs; - checkUser(context); + context.isAnonAllowed = true; return resolve.apply(this, resolverArgs); }; + + return fieldConfig; } + const { + resolve = defaultFieldResolver, + } = fieldConfig; + + fieldConfig.resolve = async function (...resolverArgs): UnknownGraphQLResolverResult { + const [, , context] = resolverArgs; + + if (!context.isAnonAllowed) { + checkUser(context); + } + + return resolve.apply(this, resolverArgs); + }; + return fieldConfig; }, }), diff --git a/src/schema.ts b/src/schema.ts index faa679bf..562e93c0 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -6,7 +6,7 @@ import { mergeTypeDefs } from '@graphql-tools/merge'; import defaultValueDirective from './directives/defaultValue'; import validateDirective from './directives/validate'; import uploadImageDirective from './directives/uploadImageDirective'; -import requireAuthDirective from './directives/requireAuth'; +import allowAnonDirective from './directives/allowAnon'; import requireAdminDirective from './directives/requireAdmin'; import requireUserInWorkspaceDirective from './directives/requireUserInWorkspace'; @@ -14,7 +14,7 @@ const { renameFromDirectiveTypeDefs, renameFromDirectiveTransformer } = renameFr const { defaultValueDirectiveTypeDefs, defaultValueDirectiveTransformer } = defaultValueDirective(); const { validateDirectiveTypeDefs, validateDirectiveTransformer } = validateDirective(); const { uploadImageDirectiveTypeDefs, uploadImageDirectiveTransformer } = uploadImageDirective(); -const { requireAuthDirectiveTypeDefs, requireAuthDirectiveTransformer } = requireAuthDirective(); +const { allowAnonDirectiveTypeDefs, allowAnonDirectiveTransformer } = allowAnonDirective(); const { requireAdminDirectiveTypeDefs, requireAdminDirectiveTransformer } = requireAdminDirective(); const { requireUserInWorkspaceDirectiveTypeDefs, requireUserInWorkspaceDirectiveTransformer } = requireUserInWorkspaceDirective(); @@ -24,7 +24,7 @@ let schema = makeExecutableSchema({ defaultValueDirectiveTypeDefs, validateDirectiveTypeDefs, uploadImageDirectiveTypeDefs, - requireAuthDirectiveTypeDefs, + allowAnonDirectiveTypeDefs, requireAdminDirectiveTypeDefs, requireUserInWorkspaceDirectiveTypeDefs, ...typeDefs, @@ -36,8 +36,8 @@ schema = renameFromDirectiveTransformer(schema); schema = defaultValueDirectiveTransformer(schema); schema = validateDirectiveTransformer(schema); schema = uploadImageDirectiveTransformer(schema); -schema = requireAuthDirectiveTransformer(schema); schema = requireAdminDirectiveTransformer(schema); +schema = allowAnonDirectiveTransformer(schema); schema = requireUserInWorkspaceDirectiveTransformer(schema); export default schema; diff --git a/src/typeDefs/billing.ts b/src/typeDefs/billing.ts index 12b3bc0a..f277fbca 100644 --- a/src/typeDefs/billing.ts +++ b/src/typeDefs/billing.ts @@ -277,12 +277,12 @@ extend type Query { """ Get workspace billing history """ - businessOperations("Workspaces IDs" ids: [ID!] = []): [BusinessOperation!]! @requireAuth @requireAdmin + businessOperations("Workspaces IDs" ids: [ID!] = []): [BusinessOperation!]! @requireAdmin """ Prepare payment data before charge (GraphQL version of composePayment) """ - composePayment(input: ComposePaymentInput!): ComposePaymentResponse! @requireAuth + composePayment(input: ComposePaymentInput!): ComposePaymentResponse! } """ @@ -324,18 +324,18 @@ extend type Mutation { """ Remove card """ - removeCard(cardNumber: String!): Boolean! @requireAuth + removeCard(cardNumber: String!): Boolean! """ Mutation for processing payment with saved card """ payWithCard( input: PayWithCardInput! - ): PayWithCardResponse! @requireAuth + ): PayWithCardResponse! """ Returns JSON data with payment link and initiate card attach procedure """ - attachCard(language: String): BillingSession! @requireAuth + attachCard(language: String): BillingSession! } `; diff --git a/src/typeDefs/event.ts b/src/typeDefs/event.ts index cd494ad1..ead9af4a 100644 --- a/src/typeDefs/event.ts +++ b/src/typeDefs/event.ts @@ -53,7 +53,7 @@ type Release { """ Release commits """ - commits: [Commit!]! + commits: [Commit!] } """ @@ -290,7 +290,7 @@ type Event { User's local timezone offset in minutes """ timezoneOffset: Int! = 0 - ): [ChartDataItem!]! @requireAuth + ): [ChartDataItem!]! } """ @@ -332,7 +332,7 @@ type Subscription { """ Sends new events from all user projects """ - eventOccurred: Event! @requireAuth + eventOccurred: Event! } """ @@ -404,14 +404,14 @@ type EventsMutations { """ updateAssignee( input: UpdateAssigneeInput! - ): UpdateAssigneeResponse! @requireAuth @requireUserInWorkspace + ): UpdateAssigneeResponse! @requireUserInWorkspace """ Remove an assignee from the selected event """ removeAssignee( input: RemoveAssigneeInput! - ): RemoveAssigneeResponse! @requireAuth @requireUserInWorkspace + ): RemoveAssigneeResponse! @requireUserInWorkspace } extend type Mutation { @@ -428,7 +428,7 @@ extend type Mutation { ID of the event to visit """ eventId: ID! - ): Boolean! @requireAuth + ): Boolean! """ Mutation sets or unsets passed mark to event @@ -448,7 +448,7 @@ extend type Mutation { Mark to set """ mark: EventMark! - ): Boolean! @requireAuth + ): Boolean! """ Namespace that contains only mutations related to the events diff --git a/src/typeDefs/user.ts b/src/typeDefs/user.ts index 2d8aa25b..93b13b1a 100644 --- a/src/typeDefs/user.ts +++ b/src/typeDefs/user.ts @@ -90,7 +90,7 @@ export default gql` """ Returns authenticated user data """ - me: User @requireAuth + me: User } extend type Mutation { @@ -107,7 +107,7 @@ export default gql` UTM parameters """ utm: UtmInput - ): ${isE2E ? 'String!' : 'Boolean!'} + ): ${isE2E ? 'String!' : 'Boolean!'} @allowAnon """ Login user with provided email and password @@ -122,7 +122,7 @@ export default gql` User password """ password: String! @validate(notEmpty: true) - ): Tokens! + ): Tokens! @allowAnon """ Update user's tokens pair @@ -132,7 +132,7 @@ export default gql` Refresh token for getting new token pair """ refreshToken: String! - ): Tokens! + ): Tokens! @allowAnon """ Reset user's password @@ -142,7 +142,7 @@ export default gql` User email """ email: String! @validate(isEmail: true) - ): Boolean! + ): Boolean! @allowAnon """ Update user's profile @@ -162,7 +162,7 @@ export default gql` User image file """ image: Upload @uploadImage - ): Boolean! @requireAuth + ): Boolean! """ Change user password @@ -177,6 +177,6 @@ export default gql` New user password """ newPassword: String! @validate(notEmpty: true) - ): Boolean! @requireAuth + ): Boolean! } `; diff --git a/src/typeDefs/userNotificationsMutations.ts b/src/typeDefs/userNotificationsMutations.ts index 5fa1bc59..4145aa4e 100644 --- a/src/typeDefs/userNotificationsMutations.ts +++ b/src/typeDefs/userNotificationsMutations.ts @@ -32,7 +32,7 @@ export default gql` Channel data to update """ input: NotificationsChannelsInput! - ): changeUserNotificationsChannelResponse! @requireAuth + ): changeUserNotificationsChannelResponse! """ Toggle user notifications receive type active status @@ -42,6 +42,6 @@ export default gql` Receive type with its new is-enabled value """ input: ChangeUserNotificationsReceiveTypeInput! - ): changeUserNotificationsReceiveTypeResponse! @requireAuth + ): changeUserNotificationsReceiveTypeResponse! } `; diff --git a/src/typeDefs/workspace.ts b/src/typeDefs/workspace.ts index 045c4272..8cc24314 100644 --- a/src/typeDefs/workspace.ts +++ b/src/typeDefs/workspace.ts @@ -130,7 +130,7 @@ export default gql` Project(s) id(s) """ ids: [ID!] = [] - ): [Project!] @requireAuth + ): [Project!] } extend type Query { @@ -138,7 +138,7 @@ export default gql` Returns workspace(s) info If ids = [] returns all user's workspaces """ - workspaces("Workspace(s) id(s)" ids: [ID] = []): [Workspace] @requireAuth + workspaces("Workspace(s) id(s)" ids: [ID] = []): [Workspace] } extend type Mutation { @@ -160,7 +160,7 @@ export default gql` New workspace image """ image: Upload @uploadImage - ): Workspace! @requireAuth + ): Workspace! """ Invite user to workspace @@ -176,7 +176,7 @@ export default gql` id of the workspace to which the user is invited """ workspaceId: ID! - ): Boolean! @requireAuth + ): Boolean! """ Update workspace settings @@ -211,7 +211,7 @@ export default gql` Workspace invite hash from link """ inviteHash: String! - ): UpdateWorkspaceResponse! @requireAuth + ): UpdateWorkspaceResponse! """ Confirm invitation to workspace @@ -227,7 +227,7 @@ export default gql` Id of the workspace to which the user was invited """ workspaceId: ID! - ): UpdateWorkspaceResponse! @requireAuth + ): UpdateWorkspaceResponse! """ Grant admin permissions @@ -280,6 +280,6 @@ export default gql` Workspace ID """ workspaceId: ID! - ): Boolean! @requireAuth + ): Boolean! } `;