diff --git a/client/src/app/components/users/users-table/users-table.component.html b/client/src/app/components/users/users-table/users-table.component.html index 287e4ebc6..1d1141b7c 100644 --- a/client/src/app/components/users/users-table/users-table.component.html +++ b/client/src/app/components/users/users-table/users-table.component.html @@ -188,12 +188,12 @@ - {{ user.statsHash.submittedEvidenceItems }} + {{ user.evidenceCount }} - {{ user.statsHash.revisions }} + {{ user.revisionCount }} diff --git a/client/src/app/generated/server.model.graphql b/client/src/app/generated/server.model.graphql index 156e2029c..b2ac1ba3b 100644 --- a/client/src/app/generated/server.model.graphql +++ b/client/src/app/generated/server.model.graphql @@ -1399,33 +1399,96 @@ type BrowseTherapyEdge { } type BrowseUser { - acceptedLicense: Boolean - areaOfExpertise: String + areaOfExpertise: AreaOfExpertise bio: String - countryId: Int - createdAt: ISO8601DateTime - deleted: Boolean - deletedAt: ISO8601DateTime + country: Country displayName: String! email: String + events( + """ + 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 + ): EventConnection! evidenceCount: Int! facebookProfile: String id: Int! - lastSeenAt: ISO8601DateTime linkedinProfile: String mostRecentActivityTimestamp: ISO8601DateTime + mostRecentConflictOfInterestStatement: Coi + mostRecentEvent: Event mostRecentOrganizationId: Int name: String + + """ + Filterable list of notifications for the logged in user. + """ + notifications( + """ + 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 + + """ + Filter the response to include only notifications generated by certain actions (ex: commenting). + """ + eventType: EventAction + + """ + Returns the first _n_ elements from the list. + """ + first: Int + + """ + Filter the response to include only notifications generated by a particular subscription. + """ + includeSeen: Boolean = false + + """ + Returns the last _n_ elements from the list. + """ + last: Int + + """ + Filter the response to include only notifications of a certain type (ex: mentions). + """ + notificationType: NotificationReason + + """ + Filter the response to include only notifications generated by a particular subscription. + """ + subscriptionId: Int + ): NotificationConnection orcid: String organizations: [Organization!]! profileImagePath(size: Int = 56): String + ranks: Ranks! revisionCount: Int! - role: String! - signupComplete: Boolean + role: UserRole! + statsHash: Stats! twitterHandle: String - updatedAt: ISO8601DateTime url: String - username: String + username: String! } """ diff --git a/client/src/app/generated/server.schema.json b/client/src/app/generated/server.schema.json index d55e06ffa..de75f5765 100644 --- a/client/src/app/generated/server.schema.json +++ b/client/src/app/generated/server.schema.json @@ -6701,25 +6701,13 @@ "name": "BrowseUser", "description": null, "fields": [ - { - "name": "acceptedLicense", - "description": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, { "name": "areaOfExpertise", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "String", + "kind": "ENUM", + "name": "AreaOfExpertise", "ofType": null }, "isDeprecated": false, @@ -6738,55 +6726,112 @@ "deprecationReason": null }, { - "name": "countryId", + "name": "country", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "Int", + "kind": "OBJECT", + "name": "Country", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "createdAt", + "name": "displayName", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "ISO8601DateTime", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "deleted", + "name": "email", "description": null, "args": [], "type": { "kind": "SCALAR", - "name": "Boolean", + "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "deletedAt", + "name": "events", "description": null, - "args": [], + "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": "SCALAR", - "name": "ISO8601DateTime", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "EventConnection", + "ofType": null + } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "displayName", + "name": "evidenceCount", "description": null, "args": [], "type": { @@ -6794,7 +6839,7 @@ "name": null, "ofType": { "kind": "SCALAR", - "name": "String", + "name": "Int", "ofType": null } }, @@ -6802,7 +6847,7 @@ "deprecationReason": null }, { - "name": "email", + "name": "facebookProfile", "description": null, "args": [], "type": { @@ -6814,7 +6859,7 @@ "deprecationReason": null }, { - "name": "evidenceCount", + "name": "id", "description": null, "args": [], "type": { @@ -6830,7 +6875,7 @@ "deprecationReason": null }, { - "name": "facebookProfile", + "name": "linkedinProfile", "description": null, "args": [], "type": { @@ -6842,23 +6887,7 @@ "deprecationReason": null }, { - "name": "id", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "lastSeenAt", + "name": "mostRecentActivityTimestamp", "description": null, "args": [], "type": { @@ -6870,24 +6899,24 @@ "deprecationReason": null }, { - "name": "linkedinProfile", + "name": "mostRecentConflictOfInterestStatement", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "String", + "kind": "OBJECT", + "name": "Coi", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, { - "name": "mostRecentActivityTimestamp", + "name": "mostRecentEvent", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "ISO8601DateTime", + "kind": "OBJECT", + "name": "Event", "ofType": null }, "isDeprecated": false, @@ -6917,6 +6946,115 @@ "isDeprecated": false, "deprecationReason": null }, + { + "name": "notifications", + "description": "Filterable list of notifications for the logged in user.", + "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 + }, + { + "name": "notificationType", + "description": "Filter the response to include only notifications of a certain type (ex: mentions).", + "type": { + "kind": "ENUM", + "name": "NotificationReason", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "eventType", + "description": "Filter the response to include only notifications generated by certain actions (ex: commenting).", + "type": { + "kind": "ENUM", + "name": "EventAction", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "subscriptionId", + "description": "Filter the response to include only notifications generated by a particular subscription.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "includeSeen", + "description": "Filter the response to include only notifications generated by a particular subscription.", + "type": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + }, + "defaultValue": "false", + "isDeprecated": false, + "deprecationReason": null + } + ], + "type": { + "kind": "OBJECT", + "name": "NotificationConnection", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, { "name": "orcid", "description": null, @@ -6979,15 +7117,15 @@ "deprecationReason": null }, { - "name": "revisionCount", + "name": "ranks", "description": null, "args": [], "type": { "kind": "NON_NULL", "name": null, "ofType": { - "kind": "SCALAR", - "name": "Int", + "kind": "OBJECT", + "name": "Ranks", "ofType": null } }, @@ -6995,7 +7133,7 @@ "deprecationReason": null }, { - "name": "role", + "name": "revisionCount", "description": null, "args": [], "type": { @@ -7003,7 +7141,7 @@ "name": null, "ofType": { "kind": "SCALAR", - "name": "String", + "name": "Int", "ofType": null } }, @@ -7011,36 +7149,44 @@ "deprecationReason": null }, { - "name": "signupComplete", + "name": "role", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "ENUM", + "name": "UserRole", + "ofType": null + } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "twitterHandle", + "name": "statsHash", "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "Stats", + "ofType": null + } }, "isDeprecated": false, "deprecationReason": null }, { - "name": "updatedAt", + "name": "twitterHandle", "description": null, "args": [], "type": { "kind": "SCALAR", - "name": "ISO8601DateTime", + "name": "String", "ofType": null }, "isDeprecated": false, @@ -7063,9 +7209,13 @@ "description": null, "args": [], "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } }, "isDeprecated": false, "deprecationReason": null diff --git a/server/app/graphql/types/browse_tables/browse_user_type.rb b/server/app/graphql/types/browse_tables/browse_user_type.rb index b30c4cd21..5afe45824 100644 --- a/server/app/graphql/types/browse_tables/browse_user_type.rb +++ b/server/app/graphql/types/browse_tables/browse_user_type.rb @@ -1,36 +1,12 @@ module Types::BrowseTables - class BrowseUserType < Types::BaseObject + class BrowseUserType < Types::Entities::UserType connection_type_class(Types::Connections::BrowseTableConnection) @@role_mapping = User.roles.invert @@area_mapping = User.area_of_expertises.invert - field :id, Int, null: false - field :email, String, null: true - field :name, String, null: true - field :url, String, null: true - field :username, String, null: true - field :display_name, String, null: false - field :created_at, GraphQL::Types::ISO8601DateTime, null: true - field :updated_at, GraphQL::Types::ISO8601DateTime, null: true - field :orcid, String, null: true - field :area_of_expertise, String, null: true - field :deleted, Boolean, null: true - field :deleted_at, GraphQL::Types::ISO8601DateTime, null: true - field :role, String, null: false - field :last_seen_at, GraphQL::Types::ISO8601DateTime, null: true - field :twitter_handle, String, null: true - field :facebook_profile, String, null: true - field :linkedin_profile, String, null: true - field :accepted_license, Boolean, null: true - field :bio, String, null: true - field :signup_complete, Boolean, null: true - field :country_id, Int, null: true - field :most_recent_organization_id, Int, null: true - field :most_recent_activity_timestamp, GraphQL::Types::ISO8601DateTime, null: true field :revision_count, Int, null: false field :evidence_count, Int, null: false - field :organizations, [Types::Entities::OrganizationType], null: false def area_of_expertise @@area_mapping[object.area_of_expertise] @@ -41,18 +17,11 @@ def role end def organizations - Loaders::AssociationLoader.for(User, :organizations).load(object) - end - - profile_image_sizes = [256, 128, 64, 32, 18, 12] - field :profile_image_path, String, null: true do - argument :size, Int, required: false, default_value: 56, - validates: { - inclusion: { - in: profile_image_sizes, - message: "Size must be one of [#{profile_image_sizes.join(',')}]" - } - } + Loaders::AssociationLoader.for(MaterializedViews::UserBrowseTableRow, :affiliations).load(object).then do |affil| + affil.map do |a| + Loaders::AssociationLoader.for(Affiliation, :organization).load(a) + end + end end end -end \ No newline at end of file +end diff --git a/server/app/jobs/refresh_materialized_views.rb b/server/app/jobs/refresh_materialized_views.rb index af38f0b4d..eedef17e3 100644 --- a/server/app/jobs/refresh_materialized_views.rb +++ b/server/app/jobs/refresh_materialized_views.rb @@ -9,7 +9,9 @@ def perform(kwargs) MaterializedViews::SourceBrowseTableRow, MaterializedViews::VariantBrowseTableRow, MaterializedViews::VariantGroupBrowseTableRow, - MaterializedViews::MolecularProfileBrowseTableRow + MaterializedViews::MolecularProfileBrowseTableRow, + MaterializedViews::UserBrowseTableRow, + MaterializedViews::OrganizationBrowseTableRow ] elsif views == 'features_only' [ @@ -21,7 +23,9 @@ def perform(kwargs) MaterializedViews::SourceBrowseTableRow, MaterializedViews::VariantBrowseTableRow, MaterializedViews::VariantGroupBrowseTableRow, - MaterializedViews::MolecularProfileBrowseTableRow + MaterializedViews::MolecularProfileBrowseTableRow, + MaterializedViews::UserBrowseTableRow, + MaterializedViews::OrganizationBrowseTableRow ] else [] diff --git a/server/app/models/materialized_views/user_browse_table_row.rb b/server/app/models/materialized_views/user_browse_table_row.rb index 5c3c5c569..06ed321f3 100644 --- a/server/app/models/materialized_views/user_browse_table_row.rb +++ b/server/app/models/materialized_views/user_browse_table_row.rb @@ -1,2 +1,4 @@ class MaterializedViews::UserBrowseTableRow < MaterializedViews::MaterializedView + has_many :affiliations, primary_key: :id, foreign_key: :user_id + has_many :organizations, through: :affiliations end