From da031923284db8573bb7dc67643b93088d5d0908 Mon Sep 17 00:00:00 2001 From: Caio Almeida <117518+caiosba@users.noreply.github.com> Date: Fri, 27 Oct 2023 16:28:08 -0300 Subject: [PATCH] Exposing new fields on GraphQL API for shared feeds invitations - Adding feed_teams connection to Feed and Team - Adding feed_team (get by database ID) to the root query type - Allow feed owner to delete a FeedTeam Reference: CV2-3900. --- app/graph/types/feed_type.rb | 1 + app/graph/types/query_type.rb | 1 + app/graph/types/team_type.rb | 1 + app/models/ability.rb | 3 + lib/relay.idl | 68 ++++++++++ public/relay.json | 240 ++++++++++++++++++++++++++++++++++ test/models/ability_test.rb | 30 +++++ 7 files changed, 344 insertions(+) diff --git a/app/graph/types/feed_type.rb b/app/graph/types/feed_type.rb index 7e5593c0e4..702faaba3b 100644 --- a/app/graph/types/feed_type.rb +++ b/app/graph/types/feed_type.rb @@ -44,4 +44,5 @@ def requests(**args) field :feed_invitations, FeedInvitationType.connection_type, null: false field :teams, TeamType.connection_type, null: false + field :feed_teams, FeedTeamType.connection_type, null: false end diff --git a/app/graph/types/query_type.rb b/app/graph/types/query_type.rb index a340647923..52d20a3f4a 100644 --- a/app/graph/types/query_type.rb +++ b/app/graph/types/query_type.rb @@ -215,6 +215,7 @@ def dynamic_annotation_field(query:, only_cache: nil) feed request feed_invitation + feed_team tipline_message ].each do |type| field type, diff --git a/app/graph/types/team_type.rb b/app/graph/types/team_type.rb index 2cfb2973c1..7c28ff6350 100644 --- a/app/graph/types/team_type.rb +++ b/app/graph/types/team_type.rb @@ -293,6 +293,7 @@ def shared_teams field :saved_searches, SavedSearchType.connection_type, null: true field :project_groups, ProjectGroupType.connection_type, null: true field :feeds, FeedType.connection_type, null: true + field :feed_teams, FeedTeamType.connection_type, null: false field :tipline_newsletters, TiplineNewsletterType.connection_type, null: true field :tipline_resources, TiplineResourceType.connection_type, null: true diff --git a/app/models/ability.rb b/app/models/ability.rb index 84f21cd749..f0526a34a2 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -85,6 +85,9 @@ def editor_perms end can [:create, :update, :read, :destroy], [Account, Source, TiplineNewsletter, TiplineResource, Feed, FeedTeam], :team_id => @context_team.id can [:create, :update, :destroy], FeedInvitation, { feed: { team_id: @context_team.id } } + can :destroy, FeedTeam do |obj| + obj.team.id == @context_team.id || obj.feed.team.id == @context_team.id + end can [:cud], AccountSource, source: { team: { team_users: { team_id: @context_team.id }}} %w(annotation comment dynamic task tag).each do |annotation_type| can [:cud], annotation_type.classify.constantize do |obj| diff --git a/lib/relay.idl b/lib/relay.idl index 21d3f58ea7..2646cb4eac 100644 --- a/lib/relay.idl +++ b/lib/relay.idl @@ -8430,6 +8430,27 @@ type Feed implements Node { """ last: Int ): FeedInvitationConnection! + feed_teams( + """ + Returns the elements in the list that come after the specified cursor. + """ + after: String + + """ + Returns the elements in the list that come before the specified cursor. + """ + before: String + + """ + Returns the first _n_ elements from the list. + """ + first: Int + + """ + Returns the last _n_ elements from the list. + """ + last: Int + ): FeedTeamConnection! filters: JsonStringType id: ID! licenses: [Int] @@ -8611,6 +8632,27 @@ type FeedTeam implements Node { updated_at: String } +""" +The connection type for FeedTeam. +""" +type FeedTeamConnection { + """ + A list of edges. + """ + edges: [FeedTeamEdge] + + """ + A list of nodes. + """ + nodes: [FeedTeam] + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + totalCount: Int +} + """ An edge in a connection. """ @@ -11690,6 +11732,11 @@ type Query { """ feed_invitation(id: ID!): FeedInvitation + """ + Information about the feed_team with given id + """ + feed_team(id: ID!): FeedTeam + """ Find whether a team exists """ @@ -12875,6 +12922,27 @@ type Team implements Node { description: String dynamic_search_fields_json_schema: JsonStringType feed(dbid: Int!): Feed + feed_teams( + """ + Returns the elements in the list that come after the specified cursor. + """ + after: String + + """ + Returns the elements in the list that come before the specified cursor. + """ + before: String + + """ + Returns the first _n_ elements from the list. + """ + first: Int + + """ + Returns the last _n_ elements from the list. + """ + last: Int + ): FeedTeamConnection! feeds( """ Returns the elements in the list that come after the specified cursor. diff --git a/public/relay.json b/public/relay.json index 4d93e551ed..b4e4c56506 100644 --- a/public/relay.json +++ b/public/relay.json @@ -45752,6 +45752,71 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "feed_teams", + "description": null, + "args": [ + { + "name": "after", + "description": "Returns the elements in the list that come after the specified cursor.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "before", + "description": "Returns the elements in the list that come before the specified cursor.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "first", + "description": "Returns the first _n_ elements from the list.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "last", + "description": "Returns the last _n_ elements from the list.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "FeedTeamConnection", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "filters", "description": null, @@ -46944,6 +47009,87 @@ "enumValues": null, "possibleTypes": null }, + { + "kind": "OBJECT", + "name": "FeedTeamConnection", + "description": "The connection type for FeedTeam.", + "fields": [ + { + "name": "edges", + "description": "A list of edges.", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "FeedTeamEdge", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "nodes", + "description": "A list of nodes.", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "FeedTeam", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "pageInfo", + "description": "Information to aid in pagination.", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "PageInfo", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "totalCount", + "description": null, + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, { "kind": "OBJECT", "name": "FeedTeamEdge", @@ -61529,6 +61675,35 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "feed_team", + "description": "Information about the feed_team with given id", + "args": [ + { + "name": "id", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "OBJECT", + "name": "FeedTeam", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "find_public_team", "description": "Find whether a team exists", @@ -67337,6 +67512,71 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "feed_teams", + "description": null, + "args": [ + { + "name": "after", + "description": "Returns the elements in the list that come after the specified cursor.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "before", + "description": "Returns the elements in the list that come before the specified cursor.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "first", + "description": "Returns the first _n_ elements from the list.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "last", + "description": "Returns the last _n_ elements from the list.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "FeedTeamConnection", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "feeds", "description": null, diff --git a/test/models/ability_test.rb b/test/models/ability_test.rb index e8b52f786b..cdef014064 100644 --- a/test/models/ability_test.rb +++ b/test/models/ability_test.rb @@ -1305,4 +1305,34 @@ def teardown assert ability.cannot?(:destroy, fi2) end end + + test "permissions for feed team" do + t1 = create_team + t2 = create_team + t3 = create_team + u1 = create_user + u2 = create_user + u3 = create_user + create_team_user user: u1, team: t1, role: 'admin' + create_team_user user: u2, team: t2, role: 'admin' + create_team_user user: u3, team: t3, role: 'admin' + f = create_feed team: t1 + ft2 = create_feed_team feed: f, team: t2 + ft3 = create_feed_team feed: f, team: t3 + with_current_user_and_team(u1, t1) do + ability = Ability.new + assert ability.can?(:destroy, ft2) + assert ability.can?(:destroy, ft3) + end + with_current_user_and_team(u2, t2) do + ability = Ability.new + assert ability.can?(:destroy, ft2) + assert ability.cannot?(:destroy, ft3) + end + with_current_user_and_team(u3, t3) do + ability = Ability.new + assert ability.cannot?(:destroy, ft2) + assert ability.can?(:destroy, ft3) + end + end end