private string CamlQueryBuilder(List list, ContentByQuery cbq) { // Copy the CBQW filters List <SearchQueryFilter> filters = new List <SearchQueryFilter>(); filters.AddRange(this.properties.Query.Filters); // Add the default filter filters.Add(new SearchQueryFilter() { ChainingOperatorUsedInCQWP = FilterChainingOperator.And, Fieldname = "FSObjType", Op = FilterOperator.Equals, Value = 0 }); // Sorting: if CBQW was sorted on one of the 4 allowed fields then take over the setting, else fall back to default sort (= Modified) string sortField = "Modified"; if (!string.IsNullOrEmpty(cbq.SortBy)) { if (cbq.SortBy.Equals("Title") || cbq.SortBy.Equals("FileLeafRef") || cbq.SortBy.Equals("Author")) { sortField = cbq.SortBy; } } // Sort order cannot be choosen: Modified = descending, others are ascending string sortOrder = "True"; if (sortField == "Modified") { sortOrder = "False"; } string query = ""; Query queryCaml = null; var and = LogicalJoin.And(); var or = LogicalJoin.Or(); // Do we have filters to apply? if (filters.Any()) { for (int i = 0; i < filters.Count; i++) { var queryFilter = filters[i]; var nextQueryFilter = filters[i]; if (i < filters.Count - 1) { nextQueryFilter = filters[i + 1]; } if (queryFilter.ChainingOperatorUsedInCQWP == FilterChainingOperator.And && nextQueryFilter.ChainingOperatorUsedInCQWP == FilterChainingOperator.And) { and.AddStatement(CamlFilterBuilder(queryFilter)); } else { or.AddStatement(CamlFilterBuilder(queryFilter)); } } if (or.HasStatements()) { and.AddStatement(or); } } queryCaml = Query.Build(and); query = queryCaml.GetCaml(true).Replace("\r", "").Replace("\n", ""); return($"<View Scope=\"RecursiveAll\"><Query>{query}<OrderBy><FieldRef Name=\"{sortField}\" Ascending=\"{sortOrder}\" /></OrderBy></Query><ViewFields><FieldRef Name=\"Editor\" /><FieldRef Name=\"FileLeafRef\" /><FieldRef Name=\"File_x0020_Type\" /><FieldRef Name=\"ID\" /><FieldRef Name=\"Modified\" /><FieldRef Name=\"Title\" /><FieldRef Name=\"UniqueID\" /></ViewFields><RowLimit Paged=\"false\">{cbq.ItemLimit}</RowLimit></View>"); }
/// <summary> /// Generate contentrollup (=highlighted content) web part properties coming from a content by query web part /// </summary> /// <param name="cbq">Properties coming from the content by query web part</param> /// <returns>Properties for highlighted content web part</returns> public string TransformContentByQueryWebPartToHighlightedContent(ContentByQuery cbq) { // Transformation logic // Scoped to list? if (!Guid.TryParse(cbq.ListGuid, out Guid listId)) { listId = Guid.Empty; } if (!string.IsNullOrEmpty(cbq.ListName) || listId != Guid.Empty) { // Scope to list List list = null; if (listId != Guid.Empty) { list = this.clientContext.Web.GetListById(listId); } else { list = this.clientContext.Web.GetListByTitle(cbq.ListName); } var defaultDocLib = this.clientContext.Web.DefaultDocumentLibrary(); this.clientContext.Load(defaultDocLib, p => p.Id); this.clientContext.Load(list, p => p.BaseType, p => p.Title, p => p.Id, p => p.Fields); this.clientContext.ExecuteQueryRetry(); // todo: bail out if not a document library --> should be handled by a selector // Set basic list properties this.properties.ListId = list.Id.ToString(); this.properties.LastListId = this.properties.ListId; this.properties.ListTitle = list.Title; this.properties.DataProviderId = "List"; //this.properties.DataProviderId = "Search"; this.properties.IsDefaultDocumentLibrary = defaultDocLib.Id.Equals(list.Id); // TODO: verify upper limit bound if (cbq.ItemLimit < 1) { cbq.ItemLimit = 1; } this.properties.MaxItemsPerPage = cbq.ItemLimit; // Layout properties if (cbq.DisplayColumns > 1) { SetLayoutTemplate(ContentRollupLayout.Card); } else { SetLayoutTemplate(ContentRollupLayout.List); } // construct query SearchQuery query = new SearchQuery(); // Libraries always equal to this query.ContentLocation = ContentLocation.CurrentSiteDocumentLibrary; // There's no document type filtering in CWQP query.DocumentTypes.Add(DocumentType.Any); // Map contenttypeid to 'default' content types if possible query.ContentTypes.AddRange(MapToContentTypes(cbq.ContentTypeBeginsWithId)); // Filtering var filter1 = MapToFilter(list, cbq.FilterOperator1, cbq.FilterField1, cbq.FilterField1Value, FilterChainingOperator.And); if (filter1 != null) { query.Filters.Add(filter1); } var filter2 = MapToFilter(list, cbq.FilterOperator2, cbq.FilterField2, cbq.FilterField2Value, cbq.Filter1ChainingOperator); if (filter2 != null) { query.Filters.Add(filter2); } var filter3 = MapToFilter(list, cbq.FilterOperator3, cbq.FilterField3, cbq.FilterField3Value, cbq.Filter2ChainingOperator); if (filter3 != null) { query.Filters.Add(filter3); } query.AdvancedQueryText = ""; // Set sort field // Possible sort fields are: Title, FileLeafRef, Author and Modified. Sort direction is always the same (Ascending=\"true\") except for sorting on Modified if (!string.IsNullOrEmpty(cbq.SortBy)) { if (cbq.SortBy.Equals("Modified") || cbq.SortBy.Equals("Title") || cbq.SortBy.Equals("FileLeafRef") || cbq.SortBy.Equals("Author")) { this.properties.DocumentLibrarySortField = cbq.SortBy; } else { // Fall back to default if the original CBQ uses sorting that was not allowed this.properties.DocumentLibrarySortField = "Modified"; } } // assign query this.properties.Query = query; if (this.properties.Query.Filters.Any()) { this.properties.Caml = CamlQueryBuilder(list, cbq); // ContentRollup web part first needs to be fixed to have it handle the CAML query generation //this.properties.Caml = ""; } } else { // scope to site(s) // Set basic site properties this.properties.DataProviderId = "Search"; // TODO: verify upper limit bound if (cbq.ItemLimit < 1) { cbq.ItemLimit = 1; } this.properties.MaxItemsPerPage = cbq.ItemLimit; // Layout properties if (cbq.DisplayColumns > 1) { SetLayoutTemplate(ContentRollupLayout.Card); } else { SetLayoutTemplate(ContentRollupLayout.List); } // construct query SearchQuery query = new SearchQuery(); // Libraries always equal to this query.ContentLocation = MapToContentLocation(cbq.WebUrl); // There's no document type filtering in CWQP query.DocumentTypes.Add(DocumentType.Any); // Map contenttypeid to 'default' content types if possible query.ContentTypes.AddRange(MapToContentTypes(cbq.ContentTypeBeginsWithId)); // Add default filter element (needed to show up the filters pane in the web part) query.Filters.Add(new SearchQueryFilter() { FilterType = FilterType.TitleContaining, Value = "", }); // Set sort type - default is MostRecent query.SortType = SortType.MostRecent; query.AdvancedQueryText = ""; // assign query this.properties.Query = query; } // Return the json properties for the converted web part return(HighlightedContentProperties()); }