Example #1
0
 public void RemoveRequest(int index)
 {
     if (index >= 0 && index < SearchRequests.Count)
     {
         SearchRequests.RemoveAt(index);
     }
 }
Example #2
0
        internal void OnChatStarted(ChatInfo chatInfo)
        {
            SearchRequests.Pop();
            ActiveChats.Add(chatInfo);

            ChatStarted?.Invoke(this, new ChatEventArgs(ChatState.Started, chatInfo));
        }
Example #3
0
        public async Task StartNewChat(Location where = Location.EntirePoland)
        {
            SearchRequests.Push(true);

            var chatPreferences = new ChatPreferences();

            chatPreferences.Myself.Location         =
                chatPreferences.LookingFor.Location =
                    where;

            var sasPacket = new EventPacket("_sas", chatPreferences, ClientEventID);

            await SendEventPacket(sasPacket);
        }
    //A basic search doesn't have a concept of a "request user" or permissions, those are set up
    //prior to this. This function just wants to build a query based on what you give it
    protected async Task <GenericSearchResult> SearchBase(
        SearchRequests requests, Dictionary <string, object> parameterValues)
    {
        var result = new GenericSearchResult()
        {
            search = requests
        };

        //Nothing to do!
        if (requests.requests.Count == 0)
        {
            return(result);
        }

        //Fix the values to start with
        foreach (var key in parameterValues.Keys.ToList())
        {
            if (parameterValues[key] is JArray)
            {
                parameterValues[key] = ((JArray)parameterValues[key]).ToObject <List <string> >() ?? throw new InvalidOperationException($"Can't figure out value inside key {key}");
            }
        }

        //Some nice prechecks
        foreach (var request in requests.requests)
        {
            if (string.IsNullOrWhiteSpace(request.name))
            {
                request.name = request.type;
            }

            if (requests.requests.Count(x => x.name == request.name) > 1)
            {
                throw new ArgumentException($"Duplicate name {request.name} in requests! Consider using 'name' to differentiate");
            }
        }

        foreach (var request in requests.requests)
        {
            var qresult = await SearchSingle(request, parameterValues, result.databaseTimes);

            //Add the results to the USER results, AND add it to our list of values so it can
            //be used in chaining. It's just a reference, don't worry about duplication or whatever.
            result.objects.Add(request.name, qresult);
            parameterValues.Add(request.name, qresult);
        }

        return(result);
    }
Example #5
0
        private void SetUpDisconnectedState()
        {
            ConnectionInfo = null;
            ActiveChats.Clear();
            SessionID = null;

            while (SearchRequests.Count > 1)
            {
                SearchRequests.Pop();
            }

            _clientEventId = 1;

            KeepAliveTimer.Stop();
        }
    public async void SearchAsync_InMultiList()
    {
        //Write two comments with two users in them. See if chaining to that field works
        var comment1 = GetNewCommentView(AllAccessContentId);

        comment1.text = $"And it's %{NormalUserId}%";
        var comment2 = GetNewCommentView(AllAccessContentId);

        comment2.text = $"And it's also %{SuperUserId}%";

        var writtenComment1 = await writer.WriteAsync(comment1, NormalUserId);

        var writtenComment2 = await writer.WriteAsync(comment2, SuperUserId);

        //Now search specifically for those two comments, but with users chained to the uidsInText field
        var search = new SearchRequests()
        {
            requests = new List <SearchRequest> {
                new SearchRequest()
                {
                    type   = "message",
                    fields = "*",
                    query  = "id in @ids"
                },
                new SearchRequest()
                {
                    type   = "user",
                    fields = "*",
                    query  = "id in @message.uidsInText"
                }
            },
            values = new Dictionary <string, object> {
                { "ids", new[] { writtenComment1.id, writtenComment2.id } }
            }
        };

        var results = await searcher.Search(search, NormalUserId);

        var comments = searcher.ToStronglyTyped <MessageView>(results.objects["message"]);
        var users    = searcher.ToStronglyTyped <UserView>(results.objects["user"]);

        Assert.Equal(2, comments.Count);
        Assert.Equal(2, users.Count);
        Assert.Contains(writtenComment1.id, comments.Select(x => x.id));
        Assert.Contains(writtenComment2.id, comments.Select(x => x.id));
        Assert.Contains(NormalUserId, users.Select(x => x.id));
        Assert.Contains(SuperUserId, users.Select(x => x.id));
    }
    public async Task GetSearchRequestForEvents_Comment()
    {
        //Go get all activity for content 1
        var search    = new SearchRequests();
        var contentId = 1 + (int)ContentVariations.Comments;

        search.values.Add("id", contentId);
        search.requests.Add(new SearchRequest()
        {
            type   = "message",
            fields = "*",
            query  = "contentId = @id"
        });
        var baseResult = await searcher.SearchUnrestricted(search);

        var comments = searcher.ToStronglyTyped <MessageView>(baseResult.objects["message"]);

        Assert.True(comments.Count > 1); //It should be greater than 1 for content 1, because of inverse activity amounts
        foreach (var c in comments)
        {
            //The event user shouldn't matter but just in case...
            var request = queue.GetSearchRequestsForEvents(new[] { new LiveEvent(c.createUserId, UserAction.create, EventType.message_event, c.id) });
            var result  = await searcher.SearchUnrestricted(request);

            //Now, make sure the result contains content, comment, and user results.
            Assert.True(result.objects.ContainsKey("content"));
            Assert.True(result.objects.ContainsKey("message"));
            Assert.True(result.objects.ContainsKey("user"));

            //The content, when requested, MUST have permissions!!
            Assert.True(result.objects["content"].First().ContainsKey("permissions"));

            var content = searcher.ToStronglyTyped <ContentView>(result.objects["content"]);
            var comment = searcher.ToStronglyTyped <MessageView>(result.objects["message"]);
            var user    = searcher.ToStronglyTyped <UserView>(result.objects["user"]);

            Assert.Single(content);
            Assert.Single(comment);
            Assert.NotEmpty(user); //don't know how many users there will be, depends on factors

            //Make sure the content creator AND the comment user are in the user list
            Assert.True(user.Any(x => x.id == content.First().createUserId), $"Couldn't find the create user for content {contentId} ({content.First().createUserId})");
            Assert.True(user.Any(x => x.id == c.createUserId), $"Couldn't find the comment user for comment {c.id} ({c.createUserId})");
            Assert.Equal(contentId, content.First().id);
            Assert.Equal(contentId, comment.First().contentId);
            Assert.Equal(c.id, comment.First().id);
        }
    }
    public Task <ActionResult <RequestResponse> > RequestAsync([FromBody] SearchRequests search)
    {
        var sw = new Stopwatch();

        sw.Start();

        return(MatchExceptions(async() =>
        {
            var data = await CachedSearcher.Search(search, GetUserId() ?? 0);
            var result = services.mapper.Map <RequestResponse>(data);
            result.requestUser = GetUserId();
            sw.Stop();
            result.totalTime = sw.Elapsed.TotalMilliseconds;
            result.nonDbTime = result.totalTime - result.databaseTimes.Sum(x => x.Value);

            return result;
        }));
    }
    private async Task <List <ActivityView> > GetActivityForContentAsync(long id)
    {
        //Go get all activity for content 1
        var search = new SearchRequests();

        search.values.Add("id", id);
        search.requests.Add(new SearchRequest()
        {
            type   = "activity",
            fields = "*",
            query  = "contentId = @id"
        });
        var baseResult = await searcher.SearchUnrestricted(search);

        var activities = searcher.ToStronglyTyped <ActivityView>(baseResult.objects["activity"]);

        return(activities);
    }
    public async Task Regression_SearchValuesForPinned()
    {
        //Write a comment to a known content
        var comment        = GetNewCommentView(AllAccessContentId);
        var writtenComment = await writer.WriteAsync(comment, NormalUserId);

        //Now update said content to have more values
        var content = await searcher.GetById <ContentView>(AllAccessContentId);

        content.values.Add("pinned", new List <long> {
            writtenComment.id
        });
        var writtenContent = await writer.WriteAsync(content, NormalUserId);

        //Then construct a search for content and comments such that the comments are in the values
        var search = new SearchRequests()
        {
            values   = new Dictionary <string, object> {
            },
            requests = new List <SearchRequest>()
            {
                //This searches ALL content, many of which will NOT have the pinned
                new SearchRequest()
                {
                    type   = nameof(RequestType.content),
                    fields = "*"
                },
                new SearchRequest()
                {
                    type   = nameof(RequestType.message),
                    fields = "*",
                    query  = "id in @content.values.pinned"
                }
            }
        };

        var searchResult = await searcher.SearchUnrestricted(search);

        var searchMessages = searcher.ToStronglyTyped <MessageView>(searchResult.objects[nameof(RequestType.message)]);
        var searchContent  = searcher.ToStronglyTyped <MessageView>(searchResult.objects[nameof(RequestType.content)]);

        Assert.Contains(writtenComment.id, searchMessages.Select(x => x.id));
        Assert.Contains(AllAccessContentId, searchContent.Select(x => x.id));
    }
Example #11
0
        public string AddComplexRequest(string Request)
        {
            searchRequest      = new SearchRequest();
            searchRequest.Text = Request;
            pos = 0;

            try
            {
                searchRequest.SearchStuff = ParseOrExpression();
            }
            catch (RequestParsingException)
            {
                searchRequest.SearchStuff.SearchTerms = new List <SearchTerm>();
                throw new RequestParsingException();
            }

            SearchRequests.Add(searchRequest);
            return(searchRequest.Text);
        }
Example #12
0
        public void ParseAddRequest(string Request)
        {
            searchRequest = null;

            foreach (SearchRequest request in SearchRequests)
            {
                if (request.Text == Request)
                {
                    searchRequest  = request;
                    CurrentRequest = searchRequest;
                }
            }

            if (searchRequest == null)
            {
                searchRequest      = new SearchRequest();
                searchRequest.Text = Request;
            }

            pos = 0;
            try
            {
                searchRequest.SearchStuff = ParseOrExpression();
            }
            catch (RequestParsingException)
            {
                searchRequest.SearchStuff.SearchTerms = new List <SearchTerm>();
                throw new RequestParsingException();
            }

            if (ProcessTerms)
            {
                foreach (SearchTerm term in searchRequest.SearchStuff.SearchTerms)
                {
                    if (term.IsPresent)
                    {
                        term.Postings = new List <PostingsParams>();
                        if (String.IsNullOrEmpty(term.Name))
                        {
                            continue;
                        }

                        SearchTermInfo[] searchTermInfo = client.GetSearchTerms(term.Key + term.Name, 0);
                        foreach (SearchTermInfo term2 in searchTermInfo)
                        {
                            if (term.Trunc && term2.Text.StartsWith(term.Key + term.Name, StringComparison.CurrentCultureIgnoreCase) || term2.Text.Equals(term.Key + term.Name, StringComparison.CurrentCultureIgnoreCase))
                            {
                                PostingsParams Posting;
                                Posting.Text = term2.Text.Substring(term.Key.Length);

                                SearchPostingInfo[] searchPostingInfo = client.GetSearchPostings(term2.Text, 0, /*i + */ 1);
                                Posting.Mfn = new List <int>();

                                foreach (SearchPostingInfo posting in searchPostingInfo)
                                {
                                    if (!Posting.Mfn.Contains(posting.Mfn) && (term.Fields.Length == 0 || term.Fields.Contains(posting.Tag)))
                                    {
                                        Posting.Mfn.Add(posting.Mfn);
                                    }
                                }

                                term.Postings.Add(Posting);
                            }
                        }
                    }
                    term.Fields = null;
                }
            }

            if (CurrentRequest != searchRequest)
            {
                SearchRequests.Add(searchRequest);
                CurrentRequest = searchRequest;
            }
        }
Example #13
0
 public SearchStream()
 {
     SearchRequests.Subscribe(ChangeSearchRequest);
 }
 //This search is a plain search, no permission limits or user lookups.
 public async Task <GenericSearchResult> SearchUnrestricted(SearchRequests requests)
 {
     return(await SearchBase(requests.Copy(), new Dictionary <string, object>(requests.values)));
 }
    //A restricted search doesn't allow you to retrieve results that the given request user can't read
    public async Task <GenericSearchResult> Search(SearchRequests requests, long requestUserId = 0)
    {
        requests = requests.Copy();

        var      globalId  = Guid.NewGuid();
        UserView requester = new UserView() //This is a default user, make SURE all the relevant fields are set!
        {
            id     = 0,
            super  = false,
            groups = new List <long>()
        };

        //Do a (hopefully) quick lookup for the request user!
        if (requestUserId > 0)
        {
            try
            {
                //This apparently throws an exception if it fails
                requester = await GetById <UserView>(RequestType.user, requestUserId);
            }
            catch (Exception ex)
            {
                logger.LogWarning($"Error while looking up requester: {ex}");
                throw new ArgumentException($"Unknown request user {requestUserId}");
            }
        }

        //Need to add requester key to parameter list!
        var globalPre       = $"_sys{globalId.ToString().Replace("-", "")}";
        var requesterKey    = $"{globalPre}_requester";
        var groupsKey       = $"{globalPre}_groups";
        var parameterValues = new Dictionary <string, object>(requests.values);

        parameterValues.Add(requesterKey, requestUserId);
        parameterValues.Add(groupsKey, permissionService.GetPermissionIdsForUser(requester));

        //Modify the queries before giving them out to the query builder! We NEED them
        //to be absolutely restricted by permissions!
        foreach (var request in requests.requests)
        {
            //This USED to be part of the single search thing, but I want unrestricted search to be
            //truly unrestricted
            request.limit = Math.Min(request.limit > 0 ? request.limit : int.MaxValue, config.MaxIndividualResultSet);

            //This is VERY important: limit content searches based on permissions!
            if (request.type == RequestType.content.ToString()) //queryBuilder.ContentRequestTypes.Select(x => x.ToString()).Contains(request.type))
            {
                request.query = queryBuilder.CombineQueryClause(request.query, $"!permissionlimit(@{groupsKey}, id, R)");
            }
            if (request.type == RequestType.message.ToString() || request.type == RequestType.activity.ToString() ||
                request.type == RequestType.watch.ToString() || request.type == RequestType.vote.ToString() ||
                request.type == RequestType.message_aggregate.ToString() || request.type == RequestType.activity_aggregate.ToString())
            {
                request.query = queryBuilder.CombineQueryClause(request.query, $"!permissionlimit(@{groupsKey}, contentId, R)");
            }
            if (request.type == RequestType.message.ToString())
            {
                request.query = queryBuilder.CombineQueryClause(request.query, $"!receiveuserlimit(@{requesterKey})");
            }
            //Watches and variables and votes are per-user!
            if (request.type == RequestType.watch.ToString() || request.type == RequestType.uservariable.ToString() ||
                request.type == RequestType.vote.ToString())
            {
                request.query = queryBuilder.CombineQueryClause(request.query, $"userId = @{requesterKey}");
            }
            if (request.type == RequestType.adminlog.ToString())
            {
                if (!requester.super)
                {
                    throw new ForbiddenException("You must be super to access the admin logs!");
                }
            }
        }

        return(await SearchBase(requests, parameterValues));
    }
Example #16
0
    /// <summary>
    /// Construct the searchrequest that will obtain the desired data for the given list of events. The events must ALL be the same type, otherwise a search
    /// request can't be constructed!
    /// </summary>
    /// <param name="events"></param>
    /// <returns></returns>
    public SearchRequests GetSearchRequestsForEvents(IEnumerable <LiveEvent> events)
    {
        if (events.Select(x => x.type).Distinct().Count() != 1)
        {
            throw new InvalidOperationException($"GetSearchRequestForEvents called with more or less than one event type! Events: {events.Count()}");
        }

        var first    = events.First();
        var requests = new SearchRequests()
        {
            values = new Dictionary <string, object> {
                { "ids", events.Select(x => x.refId) },
                { "contentIds", events.Select(x => x.contentId).Where(x => x > 0) }
            }
        };

        var basicRequest = new Func <string, SearchRequest>(t => new SearchRequest {
            type   = t,
            fields = "*",
            query  = "id in @ids"
        });

        if (first.type == EventType.message_event)
        {
            requests.requests.Add(basicRequest(RequestType.message.ToString()));
            requests.requests.Add(GetAutoContentRequest("id in @message.contentId"));
            requests.requests.Add(new SearchRequest()
            {
                type   = RequestType.user.ToString(),
                fields = "*",
                query  = "id in @content.createUserId or id in @message.createUserId or id in @message.editUserId or id in @message.uidsInText"
            });
        }
        else if (first.type == EventType.activity_event)
        {
            requests.requests.Add(basicRequest(RequestType.activity.ToString()));
            requests.requests.Add(GetAutoContentRequest("id in @activity.contentId"));
            requests.requests.Add(GetAutoContentRequest("id in @content.parentId", Constants.ParentsKey));
            requests.requests.Add(new SearchRequest()
            {
                type   = RequestType.user.ToString(),
                fields = "*",
                query  = "id in @content.createUserId or id in @activity.userId"
            });
        }
        else if (first.type == EventType.user_event)
        {
            requests.requests.Add(basicRequest(RequestType.user.ToString()));
        }
        else if (first.type == EventType.uservariable_event)
        {
            requests.requests.Add(basicRequest(RequestType.uservariable.ToString()));
        }
        else if (first.type == EventType.watch_event)
        {
            requests.requests.Add(basicRequest(RequestType.watch.ToString()));
            requests.requests.Add(GetAutoContentRequest("id in @watch.contentId or id in @contentIds"));
        }
        else
        {
            throw new InvalidOperationException($"Can't understand event type {first.type}, event references {string.Join(",", events.Select(x => x.refId))}");
        }

        //Also, add request for related content
        //requests.requests.Add(GetAutoContentRequest("id in @contentIds", Constants.RelatedContentKey));

        return(requests);
    }