public void RemoveRequest(int index) { if (index >= 0 && index < SearchRequests.Count) { SearchRequests.RemoveAt(index); } }
internal void OnChatStarted(ChatInfo chatInfo) { SearchRequests.Pop(); ActiveChats.Add(chatInfo); ChatStarted?.Invoke(this, new ChatEventArgs(ChatState.Started, chatInfo)); }
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); }
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)); }
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); }
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; } }
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)); }
/// <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); }