feat(gql): adds streamSearch, adds pagination to userSearch
This commit is contained in:
@@ -22,6 +22,28 @@ module.exports = {
|
||||
|
||||
let stream = await getStream( { streamId: args.id } )
|
||||
return stream
|
||||
},
|
||||
async streams( parent, args, context, info ) {
|
||||
await validateScopes( context.scopes, 'streams:read' )
|
||||
|
||||
if ( args.limit && args.limit > 100 )
|
||||
throw new UserInputError( 'Cannot return more than 100 results.' )
|
||||
|
||||
let totalCount = await getUserStreamsCount( {userId: context.userId, publicOnly: false} )
|
||||
|
||||
let {cursor, streams} = await getUserStreams( {userId: context.userId, limit: args.limit, cursor: args.cursor, publicOnly: false} )
|
||||
return {totalCount, cursor: cursor, items: streams}
|
||||
},
|
||||
async streamSearch( parent, args, context, info ) {
|
||||
await validateScopes( context.scopes, 'streams:read' )
|
||||
|
||||
if ( args.limit && args.limit > 100 )
|
||||
throw new UserInputError( 'Cannot return more than 100 results.' )
|
||||
|
||||
let totalCount = await getUserStreamsCount( {userId: context.userId, publicOnly: false, searchQuery: args.query} )
|
||||
|
||||
let {cursor, streams} = await getUserStreams( {userId: context.userId, limit: args.limit, cursor: args.cursor, publicOnly: false, searchQuery: args.query} )
|
||||
return {totalCount, cursor: cursor, items: streams}
|
||||
}
|
||||
},
|
||||
Stream: {
|
||||
@@ -35,6 +57,8 @@ module.exports = {
|
||||
User: {
|
||||
|
||||
async streams( parent, args, context, info ) {
|
||||
if ( args.limit && args.limit > 100 )
|
||||
throw new UserInputError( 'Cannot return more than 100 results.' )
|
||||
// Return only the user's public streams if parent.id !== context.userId
|
||||
let publicOnly = parent.id !== context.userId
|
||||
let totalCount = await getUserStreamsCount( { userId: parent.id, publicOnly } )
|
||||
|
||||
@@ -29,24 +29,20 @@ module.exports = {
|
||||
return await getUser( args.id || context.userId )
|
||||
},
|
||||
|
||||
async userSearchResults( parent, args, context, info ) {
|
||||
async userSearch( parent, args, context, info ) {
|
||||
await validateServerRole( context, 'server:user' )
|
||||
await validateScopes( context.scopes, 'profile:read' )
|
||||
await validateScopes( context.scopes, 'users:read' )
|
||||
|
||||
if ( !args.query ) {
|
||||
throw new UserInputError( 'You must provide a search query.' )
|
||||
}
|
||||
|
||||
if ( args.query.length < 3 ) {
|
||||
if ( args.query.length < 3 )
|
||||
throw new UserInputError( 'Search query must be at least 3 carachters.' )
|
||||
}
|
||||
|
||||
|
||||
if ( args.limit && args.limit > 100 ) {
|
||||
if ( args.limit && args.limit > 100 )
|
||||
throw new UserInputError( 'Cannot return more than 100 results.' )
|
||||
}
|
||||
|
||||
return await searchUsers( args.query, args.limit )
|
||||
|
||||
let {cursor, users} = await searchUsers( args.query, args.limit, args.cursor )
|
||||
return {cursor: cursor, items: users}
|
||||
},
|
||||
|
||||
async userPwdStrength( parent, args, context, info ) {
|
||||
@@ -1,5 +1,7 @@
|
||||
extend type Query {
|
||||
stream( id: String! ): Stream
|
||||
streams( limit: Int! = 100, cursor: String ): StreamCollection
|
||||
streamSearch( query: String!, limit: Int! = 100, cursor: String ): StreamCollection
|
||||
}
|
||||
|
||||
type Stream {
|
||||
@@ -16,7 +18,7 @@ extend type User {
|
||||
"""
|
||||
All the streams that a user has access to.
|
||||
"""
|
||||
streams( limit: Int! = 20, cursor: String ): StreamCollectionUser
|
||||
streams( limit: Int! = 20, cursor: String ): StreamCollection
|
||||
}
|
||||
|
||||
type StreamCollaborator {
|
||||
@@ -25,12 +27,13 @@ type StreamCollaborator {
|
||||
role: String!
|
||||
}
|
||||
|
||||
type StreamCollectionUser {
|
||||
type StreamCollection {
|
||||
totalCount: Int!
|
||||
cursor: String
|
||||
items: [ Stream ]
|
||||
}
|
||||
|
||||
|
||||
extend type Mutation {
|
||||
"""
|
||||
Creates a new stream.
|
||||
|
||||
@@ -3,7 +3,7 @@ extend type Query {
|
||||
Gets the profile of a user. If no id argument is provided, will return the current authenticated user's profile (as extracted from the authorization header).
|
||||
"""
|
||||
user( id: String ): User
|
||||
userSearchResults(query: String, limit: Int! = 100): [UserSearchResult!]!
|
||||
userSearch( query: String!, limit: Int! = 100, cursor: String ): UserSearchResultCollection
|
||||
userPwdStrength( pwd: String! ): JSONObject
|
||||
}
|
||||
|
||||
@@ -23,6 +23,11 @@ type User {
|
||||
role: String
|
||||
}
|
||||
|
||||
type UserSearchResultCollection {
|
||||
cursor: String
|
||||
items: [ UserSearchResult ]
|
||||
}
|
||||
|
||||
type UserSearchResult {
|
||||
id: String!
|
||||
username: String
|
||||
|
||||
@@ -10,7 +10,6 @@ const BranchCommits = ( ) => knex( 'branch_commits' )
|
||||
module.exports = {
|
||||
|
||||
async createBranch( { name, description, streamId, authorId } ) {
|
||||
|
||||
let branch = {}
|
||||
branch.id = crs( { length: 10 } )
|
||||
branch.streamId = streamId
|
||||
|
||||
@@ -89,10 +89,10 @@ module.exports = {
|
||||
return await Streams( ).where( { id: streamId } ).del( )
|
||||
},
|
||||
|
||||
async getUserStreams( { userId, limit, cursor, publicOnly } ) {
|
||||
async getUserStreams( {userId, limit, cursor, publicOnly, searchQuery } ) {
|
||||
limit = limit || 100
|
||||
publicOnly = publicOnly !== false //defaults to true if not provided
|
||||
|
||||
let likeQuery = "%" + searchQuery + "%"
|
||||
let query = Acl( )
|
||||
.columns( [ { id: 'streams.id' }, 'name', 'description', 'isPublic', 'createdAt', 'updatedAt', 'role' ] ).select( )
|
||||
.join( 'streams', 'stream_acl.resourceId', 'streams.id' )
|
||||
@@ -104,16 +104,22 @@ module.exports = {
|
||||
if ( publicOnly )
|
||||
query.andWhere( 'streams.isPublic', true )
|
||||
|
||||
if ( searchQuery )
|
||||
query.andWhere( function () {
|
||||
this.where( 'name', 'ILIKE', likeQuery )
|
||||
.orWhere( 'description', 'ILIKE', likeQuery )
|
||||
.orWhere( 'id', 'ILIKE', likeQuery ) //potentially useless?
|
||||
} )
|
||||
|
||||
query.orderBy( 'streams.updatedAt', 'desc' ).limit( limit )
|
||||
|
||||
let rows = await query
|
||||
return { streams: rows, cursor: rows.length > 0 ? rows[ rows.length - 1 ].updatedAt.toISOString( ) : null }
|
||||
},
|
||||
|
||||
async getUserStreamsCount( { userId, publicOnly } ) {
|
||||
|
||||
async getUserStreamsCount( {userId, publicOnly, searchQuery } ) {
|
||||
publicOnly = publicOnly !== false //defaults to true if not provided
|
||||
|
||||
let likeQuery = "%" + searchQuery + "%"
|
||||
let query = Acl( ).count( )
|
||||
.join( 'streams', 'stream_acl.resourceId', 'streams.id' )
|
||||
.where( { userId: userId } )
|
||||
@@ -121,6 +127,13 @@ module.exports = {
|
||||
if ( publicOnly )
|
||||
query.andWhere( 'streams.isPublic', true )
|
||||
|
||||
if ( searchQuery )
|
||||
query.andWhere( function () {
|
||||
this.where( 'name', 'ILIKE', likeQuery )
|
||||
.orWhere( 'description', 'ILIKE', likeQuery )
|
||||
.orWhere( 'id', 'ILIKE', likeQuery ) //potentially useless?
|
||||
} )
|
||||
|
||||
let [ res ] = await query
|
||||
return parseInt( res.count )
|
||||
},
|
||||
@@ -128,10 +141,10 @@ module.exports = {
|
||||
async getStreamUsers( { streamId } ) {
|
||||
let query =
|
||||
Acl( ).columns( { role: 'stream_acl.role' }, 'id', 'name' ).select( )
|
||||
.where( { resourceId: streamId } )
|
||||
.rightJoin( 'users', { 'users.id': 'stream_acl.userId' } )
|
||||
.select( 'stream_acl.role', 'username', 'name', 'id' )
|
||||
.orderBy( 'stream_acl.role' )
|
||||
.where( { resourceId: streamId } )
|
||||
.rightJoin( 'users', { 'users.id': 'stream_acl.userId' } )
|
||||
.select( 'stream_acl.role', 'username', 'name', 'id' )
|
||||
.orderBy( 'stream_acl.role' )
|
||||
|
||||
return await query
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ const appRoot = require( 'app-root-path' )
|
||||
const knex = require( `${appRoot}/db/knex` )
|
||||
|
||||
const Users = () => knex( 'users' )
|
||||
const ServerRoles = () => knex( 'server_acl' )
|
||||
const Acl = () => knex( 'server_acl' )
|
||||
|
||||
module.exports = {
|
||||
|
||||
@@ -16,7 +16,7 @@ module.exports = {
|
||||
*/
|
||||
|
||||
async createUser( user ) {
|
||||
let [ {count} ] = await ServerRoles().where( {role: 'server:admin'} ).count()
|
||||
let [ {count} ] = await Acl().where( {role: 'server:admin'} ).count()
|
||||
|
||||
user.id = crs( {length: 10} )
|
||||
|
||||
@@ -31,9 +31,9 @@ module.exports = {
|
||||
let res = await Users().returning( 'id' ).insert( user )
|
||||
|
||||
if ( parseInt( count ) === 0 ) {
|
||||
await ServerRoles().insert( {userId: res[0], role: 'server:admin'} )
|
||||
await Acl().insert( {userId: res[0], role: 'server:admin'} )
|
||||
} else {
|
||||
await ServerRoles().insert( {userId: res[0], role: 'server:user'} )
|
||||
await Acl().insert( {userId: res[0], role: 'server:user'} )
|
||||
}
|
||||
|
||||
return res[0]
|
||||
@@ -70,7 +70,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
async getUserRole( id ) {
|
||||
let {role} = await ServerRoles().where( {userId: id} ).select( 'role' ).first()
|
||||
let {role} = await Acl().where( {userId: id} ).select( 'role' ).first()
|
||||
return role
|
||||
},
|
||||
|
||||
@@ -82,16 +82,23 @@ module.exports = {
|
||||
await Users().where( {id: id} ).update( user )
|
||||
},
|
||||
|
||||
async searchUsers( query, limit ) {
|
||||
async searchUsers( searchQuery, limit, cursor ) {
|
||||
limit = limit || 100
|
||||
let likeQuery = "%" + query + "%"
|
||||
let users = await Users()
|
||||
.where( {email: query} ) //match full email or partial username / name
|
||||
.orWhere( 'username', 'like', likeQuery )
|
||||
.orWhere( 'name', 'like', likeQuery )
|
||||
.limit( limit )
|
||||
let likeQuery = "%" + searchQuery + "%"
|
||||
let query = Users()
|
||||
.where( function () {
|
||||
this.where( {email: searchQuery} ) //match full email or partial username / name
|
||||
.orWhere( 'username', 'ILIKE', likeQuery )
|
||||
.orWhere( 'name', 'ILIKE', likeQuery )
|
||||
} )
|
||||
|
||||
return users
|
||||
if ( cursor )
|
||||
query.andWhere( 'users.createdAt', '<', cursor )
|
||||
|
||||
query.orderBy( 'users.createdAt', 'desc' ).limit( limit )
|
||||
|
||||
let rows = await query
|
||||
return {users: rows, cursor: rows.length > 0 ? rows[rows.length - 1].createdAt.toISOString() : null}
|
||||
},
|
||||
|
||||
async validatePasssword( {email, password} ) {
|
||||
|
||||
Reference in New Issue
Block a user