diff --git a/backend/src/db/factories.js b/backend/src/db/factories.js
index 010ef67ad..e0280bed4 100644
--- a/backend/src/db/factories.js
+++ b/backend/src/db/factories.js
@@ -64,7 +64,7 @@ Factory.define('basicUser')
password: '1234',
role: 'user',
about: faker.lorem.paragraph,
- termsAndConditionsAgreedVersion: '0.0.1',
+ termsAndConditionsAgreedVersion: '0.0.4',
termsAndConditionsAgreedAt: '2019-08-01T10:47:19.212Z',
allowEmbedIframes: false,
showShoutsPublicly: false,
diff --git a/backend/src/db/seed.js b/backend/src/db/seed.js
index 953f80b55..782d52d0c 100644
--- a/backend/src/db/seed.js
+++ b/backend/src/db/seed.js
@@ -929,7 +929,24 @@ const languages = ['de', 'en', 'es', 'fr', 'it', 'pt', 'pl']
])
await Promise.all([...Array(30).keys()].map(() => Factory.build('user')))
-
+ await Promise.all(
+ [...Array(30).keys()].map(index => Factory.build('user', { name: `Jenny${index}` })),
+ )
+ await Promise.all(
+ [...Array(30).keys()].map(() =>
+ Factory.build(
+ 'post',
+ { content: `Jenny ${faker.lorem.sentence()}` },
+ {
+ categoryIds: ['cat1'],
+ author: jennyRostock,
+ image: Factory.build('image', {
+ url: faker.image.unsplash.objects(),
+ }),
+ },
+ ),
+ ),
+ )
await Promise.all(
[...Array(30).keys()].map(() =>
Factory.build(
diff --git a/backend/src/middleware/permissionsMiddleware.js b/backend/src/middleware/permissionsMiddleware.js
index dcb6f8973..e9807c3c2 100644
--- a/backend/src/middleware/permissionsMiddleware.js
+++ b/backend/src/middleware/permissionsMiddleware.js
@@ -87,6 +87,8 @@ export default shield(
findPosts: allow,
findUsers: allow,
searchResults: allow,
+ searchPosts: allow,
+ searchUsers: allow,
embed: allow,
Category: allow,
Tag: allow,
diff --git a/backend/src/schema/resolvers/searches.js b/backend/src/schema/resolvers/searches.js
index 0cf5c4ae8..eff8cd082 100644
--- a/backend/src/schema/resolvers/searches.js
+++ b/backend/src/schema/resolvers/searches.js
@@ -5,6 +5,89 @@ import { queryString } from './searches/queryString'
export default {
Query: {
+ searchPosts: async (_parent, args, context, _resolveInfo) => {
+ const { query, postsOffset, firstPosts } = args
+ const { id: userId } = context.user
+
+ const postCypher = `
+ CALL db.index.fulltext.queryNodes('post_fulltext_search', $query)
+ YIELD node as posts, score
+ MATCH (posts)<-[:WROTE]-(author:User)
+ WHERE score >= 0.0
+ AND NOT (
+ author.deleted = true OR author.disabled = true
+ OR posts.deleted = true OR posts.disabled = true
+ OR (:User {id: $userId})-[:MUTED]->(author)
+ )
+ WITH posts, author,
+ [(posts)<-[:COMMENTS]-(comment:Comment) | comment] as comments,
+ [(posts)<-[:SHOUTED]-(user:User) | user] as shouter
+ RETURN posts {
+ .*,
+ __typename: labels(posts)[0],
+ author: properties(author),
+ commentsCount: toString(size(comments)),
+ shoutedCount: toString(size(shouter))
+ }
+ SKIP $postsOffset
+ LIMIT $firstPosts
+ `
+
+ const myQuery = queryString(query)
+
+ const session = context.driver.session()
+ const searchResultPromise = session.readTransaction(async transaction => {
+ const postTransactionResponse = await transaction.run(postCypher, {
+ query: myQuery,
+ postsOffset,
+ firstPosts,
+ userId,
+ })
+ return postTransactionResponse
+ })
+ try {
+ const postResults = await searchResultPromise
+ log(postResults)
+ return postResults.records.map(record => record.get('posts'))
+ } finally {
+ session.close()
+ }
+ },
+ searchUsers: async (_parent, args, context, _resolveInfo) => {
+ const { query, usersOffset, firstUsers } = args
+ const { id: userId } = context.user
+
+ const userCypher = `
+ CALL db.index.fulltext.queryNodes('user_fulltext_search', $query)
+ YIELD node as users, score
+ MATCH (users)
+ WHERE score >= 0.0
+ AND NOT (users.deleted = true OR users.disabled = true)
+ RETURN users {.*, __typename: labels(users)[0]}
+ SKIP $usersOffset
+ LIMIT $firstUsers
+ `
+ const myQuery = queryString(query)
+
+ const session = context.driver.session()
+ const searchResultPromise = session.readTransaction(async transaction => {
+ const userTransactionResponse = await transaction.run(userCypher, {
+ query: myQuery,
+ usersOffset,
+ firstUsers,
+ userId,
+ })
+ return userTransactionResponse
+ })
+
+ try {
+ const userResults = await searchResultPromise
+ log(userResults)
+ return userResults.records.map(record => record.get('users'))
+ } finally {
+ session.close()
+ }
+ },
searchResults: async (_parent, args, context, _resolveInfo) => {
const { query, limit } = args
const { id: thisUserId } = context.user
diff --git a/backend/src/schema/types/type/Search.gql b/backend/src/schema/types/type/Search.gql
index 9b8613ff8..effd7246c 100644
--- a/backend/src/schema/types/type/Search.gql
+++ b/backend/src/schema/types/type/Search.gql
@@ -1,5 +1,7 @@
union SearchResult = Post | User
type Query {
+ searchPosts(query: String!, firstPosts: Int, postsOffset: Int): [Post]!
+ searchUsers(query: String!, firstUsers: Int, usersOffset: Int): [User]!
searchResults(query: String!, limit: Int = 5): [SearchResult]!
}
diff --git a/webapp/components/_new/features/SearchResults/SearchResults.vue b/webapp/components/_new/features/SearchResults/SearchResults.vue
index e32970cf6..3b0c2d08a 100644
--- a/webapp/components/_new/features/SearchResults/SearchResults.vue
+++ b/webapp/components/_new/features/SearchResults/SearchResults.vue
@@ -9,38 +9,54 @@
icon="tasks"
:message="$t('search.no-results', { search })"
/>
-