SmartAPI
Open Source .NET RQL library for RedDot CMS / OpenText WSM Management Server
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
IExtendedPageSearch.cs
Go to the documentation of this file.
1 // SmartAPI - .Net programmatic access to RedDot servers
2 //
3 // Copyright (C) 2013 erminas GbR
4 //
5 // This program is free software: you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License as published by the Free Software Foundation,
7 // either version 3 of the License, or (at your option) any later version.
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 // See the GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License along with this program.
14 // If not, see <http://www.gnu.org/licenses/>.
15 
16 using System;
17 using System.Collections.Generic;
18 using System.Linq;
19 using System.Xml;
20 using erminas.SmartAPI.CMS.Project.ContentClasses;
21 using erminas.SmartAPI.CMS.Project.Workflows;
22 using erminas.SmartAPI.CMS.ServerManagement;
23 using erminas.SmartAPI.Exceptions;
24 using erminas.SmartAPI.Utils;
25 
26 namespace erminas.SmartAPI.CMS.Project.Pages
27 {
42  {
43  int Count();
44  List<ResultGroup> Execute();
45  List<IPageSearchFilter> Filters { get; }
46  GroupBy GroupBy { get; set; }
47  SortDirection GroupSortDirection { get; set; }
48  ILanguageVariant LanguageVariant { get; set; }
49  int MaxHits { get; set; }
50  OrderBy OrderBy { get; set; }
51  SortDirection OrderDirection { get; set; }
52  IUser User { get; set; }
53  }
54 
55  internal class ExtendedPageSearch : IExtendedPageSearch
56  {
57  private readonly List<IPageSearchFilter> _filters = new List<IPageSearchFilter>();
58 
59  private readonly IProject _project;
60 
61  public ExtendedPageSearch(IProject project)
62  {
63  _project = project;
64  }
65 
66  public int Count()
67  {
68  XmlDocument xmlDoc = RunQuery(true);
69  return
70  ((XmlElement) xmlDoc.GetElementsByTagName("PAGES")[0]).GetIntAttributeValue("hits").GetValueOrDefault();
71  }
72 
73  public List<ResultGroup> Execute()
74  {
75  return ToResult(RunQuery(false));
76  }
77 
78  public List<IPageSearchFilter> Filters
79  {
80  get { return _filters; }
81  }
82 
83  public GroupBy GroupBy { get; set; }
84 
85  public SortDirection GroupSortDirection { get; set; }
86 
87  public ILanguageVariant LanguageVariant { get; set; }
88 
89  public int MaxHits { get; set; }
90 
91  public OrderBy OrderBy { get; set; }
92 
93  public SortDirection OrderDirection { get; set; }
94 
95  public IProject Project
96  {
97  get { return _project; }
98  }
99 
100  public ISession Session
101  {
102  get { return Project.Session; }
103  }
104 
105  public IUser User { get; set; }
106 
107  private static string GroupByTypeToString(GroupBy type)
108  {
109  switch (type)
110  {
111  case GroupBy.ContentClass:
112  return "contentclass";
113  case GroupBy.CreatedBy:
114  return "createdby";
115  case GroupBy.ChangedBy:
116  return "changedby";
117  case GroupBy.None:
118  return "";
119  default:
120  throw new ArgumentException(String.Format("Unknown group by type: {0}", type));
121  }
122  }
123 
124  private ILanguageVariant LanguageVariantOfSearchResults
125  {
126  get { return LanguageVariant ?? _project.LanguageVariants.Current; }
127  }
128 
129  private static string OrderByTypeToString(OrderBy order)
130  {
131  switch (order)
132  {
133  case OrderBy.PageId:
134  return "pageid";
135  case OrderBy.Headline:
136  return "headline";
137  case OrderBy.CreationDate:
138  return "createdate";
139  case OrderBy.ChangeDate:
140  return "changedate";
141  case OrderBy.ContentClass:
142  return "contentclass";
143  default:
144  throw new ArgumentException(String.Format("Unknown sort direction: {0}", order));
145  }
146  }
147 
148  private XmlDocument RunQuery(bool isCountOnly)
149  {
150  if (Session.ServerVersion < new Version(10, 0) && Filters.Any(filter => filter is WorkflowFilter))
151  {
152  throw new InvalidServerVersionException(Session.ServerLogin,
153  "Searches for pages in workflow are not supported for RedDot servers with version < 10");
154  }
155  const string XSEARCH = @"<PAGE action=""xsearch"" {0}>{1}</PAGE>";
156  string arguments = "";
157  if (GroupBy != GroupBy.None)
158  {
159  arguments += "groupby=\"" + GroupByTypeToString(GroupBy) + "\" ";
160  arguments += "groupdirection=\"" + SortDirectionToString(GroupSortDirection) + "\" ";
161  }
162 
163  if (LanguageVariant != null)
164  {
165  arguments += "languagevariantid=\"" + LanguageVariant.Abbreviation + "\" ";
166  }
167 
168  if (isCountOnly)
169  {
170  arguments += @"option=""countresults"" ";
171  }
172 
173  arguments += "maxhits=\"" + MaxHits + "\" ";
174  arguments += "orderby=\"" + OrderByTypeToString(OrderBy) + "\" ";
175  arguments += "orderdirection=\"" + SortDirectionToString(OrderDirection) + "\" ";
176  arguments += "pagesize=\"-1\" ";
177 
178  arguments += "projectguid=\"" + _project.Guid.ToRQLString() + "\" ";
179  if (User != null)
180  {
181  arguments += "userguid=\"" + User.Guid.ToRQLString() + "\" ";
182  }
183 
184  string searchItems = "";
185  if (Filters.Any())
186  {
187  searchItems = "<SEARCHITEMS>";
188  searchItems += Filters.Aggregate("", (value, curPred) => value + curPred.ToSearchItemString());
189  searchItems += "</SEARCHITEMS>";
190  }
191 
192  return _project.ExecuteRQL(string.Format(XSEARCH, arguments, searchItems));
193  }
194 
195  private static string SortDirectionToString(SortDirection dir)
196  {
197  switch (dir)
198  {
199  case SortDirection.Ascending:
200  return "ASC";
201  case SortDirection.Descending:
202  return "DESC";
203  default:
204  throw new ArgumentException(String.Format("Unknown sort direction: {0}", dir));
205  }
206  }
207 
208  private IEnumerable<ReleaseInfo> ToReleases(XmlElement releases)
209  {
210  return (from XmlElement curRelease in releases
211  let users = curRelease.GetElementsByTagName("USER")
212  select
213  new ReleaseInfo(curRelease.GetIntAttributeValue("assentcount").GetValueOrDefault(),
214  curRelease.GetIntAttributeValue("requiredassentcount").GetValueOrDefault(),
215  from XmlElement curUser in releases.GetElementsByTagName("USER")
216  select new ReleaseInfo.UserInfo(_project, curUser))).ToList();
217  }
218 
219  private List<ResultGroup> ToResult(XmlDocument doc)
220  {
221  XmlNodeList groups = doc.GetElementsByTagName("GROUP");
222  if (groups.Count == 0)
223  {
224  return new List<ResultGroup> {new ResultGroup(null, ToResult(doc.GetElementsByTagName("PAGE")))};
225  }
226  return (from XmlElement curGroup in groups
227  select
228  new ResultGroup(curGroup.GetAttributeValue("value"),
229  ToResult(curGroup.GetElementsByTagName("PAGE")))).ToList();
230  }
231 
232  private IEnumerable<Result> ToResult(XmlNodeList pages)
233  {
234  return (from XmlElement curPage in pages
235  let creation = (XmlElement) curPage.GetElementsByTagName("CREATION")[0]
236  let change = (XmlElement) curPage.GetElementsByTagName("CHANGE")[0]
237  let release = (XmlElement) curPage.GetElementsByTagName("RELEASE")[0]
238  let contentClass = (XmlElement) curPage.GetElementsByTagName("CONTENTCLASS")[0]
239  select
240  new Result(
241  new Page(_project, curPage.GetGuid(), LanguageVariantOfSearchResults)
242  {
243  Id = curPage.GetIntAttributeValue("id").GetValueOrDefault(),
244  InitialHeadlineValue = curPage.GetAttributeValue("headline"),
245  Status = ((PageState) int.Parse(curPage.GetAttributeValue("status")))
246  },
247  // ReSharper disable PossibleInvalidOperationException
248  creation.GetOADate().Value,
249  new User(_project.Session, ((XmlElement) creation.GetElementsByTagName("USER")[0]).GetGuid()),
250  change.GetOADate().Value, // ReSharper restore PossibleInvalidOperationException
251  new User(_project.Session, ((XmlElement) change.GetElementsByTagName("USER")[0]).GetGuid()),
252  new ContentClass(_project, contentClass.GetGuid())
253  {
254  Name = contentClass.GetAttributeValue("name")
255  })
256  {
257  WorkflowInfo = ToWorkflow(curPage.GetElementsByTagName("WORKFLOW"))
258  }).ToList();
259  }
260 
261  private WorkflowInfo ToWorkflow(XmlNodeList workflows)
262  {
263  if (workflows.Count == 0)
264  {
265  return null;
266  }
267 
268  var workflowElement = (XmlElement) workflows[0];
269  int? skipable = workflowElement.GetIntAttributeValue("skipable");
270  var workflow = new Workflow(_project, workflowElement.GetGuid())
271  {
272  Name = workflowElement.GetAttributeValue("name")
273  };
274  return new WorkflowInfo(workflow,
275  ToReleases((XmlElement) workflowElement.GetElementsByTagName("RELEASES")[0]),
276  workflowElement.GetAttributeValue("releasename"),
277  (WorkflowInfo.Rejection) workflowElement.GetIntAttributeValue("rejectiontype"),
278  (WorkflowInfo.ReleaseType) workflowElement.GetIntAttributeValue("releasetype"),
279  skipable == null
280  ? WorkflowInfo.RejectionSkippableType.NotApplicable
281  : (WorkflowInfo.RejectionSkippableType) skipable.Value,
282  workflowElement.GetIntAttributeValue("escalationtimeout").Value,
283  from XmlElement curSupplement in workflowElement.GetElementsByTagName("SUPPLEMENT")
284  select new Note(workflow, curSupplement));
285  }
286  }
287 
288  public enum SortDirection
289  {
290  Ascending = 0,
291  Descending
292  }
293 
294  public enum OrderBy
295  {
296  Headline = 0,
297  PageId,
298  CreationDate,
299  ChangeDate,
300  ContentClass
301  }
302 
303  public enum GroupBy
304  {
305  None = 0,
306  ContentClass,
307  CreatedBy,
308  ChangedBy
309  }
310 }