SmartAPI
Open Source .NET RQL library for RedDot CMS / OpenText WSM Management Server
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
IContentClass.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;
18 using System.Collections.Generic;
19 using System.Linq;
20 using System.Xml;
21 using erminas.SmartAPI.CMS.Converter;
22 using erminas.SmartAPI.CMS.Project.ContentClasses.Elements;
23 using erminas.SmartAPI.CMS.Project.Folder;
24 using erminas.SmartAPI.CMS.Project.Keywords;
25 using erminas.SmartAPI.CMS.Project.Pages;
26 using erminas.SmartAPI.CMS.ServerManagement;
27 using erminas.SmartAPI.Exceptions;
28 using erminas.SmartAPI.Utils;
29 using erminas.SmartAPI.Utils.CachedCollections;
30 
31 namespace erminas.SmartAPI.CMS.Project.ContentClasses
32 {
34  {
38  void Commit();
39 
45  void CopyElementsToContentClass(IContentClass targetCC, params string[] elementNames);
46 
52  void CopyToProject(IProject project, Guid targetFolderGuid);
53 
57  string DescriptionInCurrentDisplayLanguage { get; set; }
58 
62  IContentClassEditableAreaSettings EditableAreaSettings { get; }
63 
64  IContentClassElements Elements { get; }
65 
66  ICollection<IPage> Pages { get; }
67 
71  IContentClassFolder Folder { get; }
72 
73  bool IsAvailableViaTheShortcutMenuInSmartEdit { get; set; }
74 
75  [VersionIsGreaterThanOrEqual(9, 0, 0, 41, VersionName = "Version 9 Hotfix 5")]
76  bool IsChangingHeadlineEffectiveForAllLanguageVariants { get; set; }
77 
78  bool IsKeywordRequired { get; set; }
79 
80  bool IsNotRelevantForGlobalContentWorkflow { get; set; }
81 
82  IPageDefinitions PageDefinitions { get; }
83 
87  IPreassignedKeywords PreassignedKeywords { get; }
88 
92  ISyllable Prefix { get; }
93 
94  IProjectVariantAssignments ProjectVariantAssignments { get; }
95 
96  ICategory RequiredKeywordCategory { get; set; }
97 
101  ISyllable Suffix { get; }
102 
103  ITemplateVariants TemplateVariants { get; }
104 
108  IContentClassVersions Versions { get; }
109  }
110 
114  internal class ContentClass : PartialRedDotProjectObject, IContentClass
115  {
116  internal ContentClass(IProject project, XmlElement xmlElement) : base(project, xmlElement)
117  {
118  Init();
119  //TODO sharedrights = 1 bei ccs von anderen projekten
120  }
121 
122  internal ContentClass(IProject project, Guid guid) : base(project, guid)
123  {
124  Init();
125  //TODO sharedrights = 1 bei ccs von anderen projekten
126  }
127 
131  public void Commit()
132  {
133  //if it isn't even initialized, nothing was changed
134  if (!IsInitialized)
135  {
136  return;
137  }
138 
139  var query = GetSaveString(_readWriteWrapper.MergedElement);
140  Project.ExecuteRQL(query, RqlType.SessionKeyInProject);
141  }
142 
148  public void CopyElementsToContentClass(IContentClass targetCC, params string[] elementNames)
149  {
150  if (elementNames == null || elementNames.Length == 0)
151  {
152  return;
153  }
154 
155  var createdElements = new Dictionary<string, IContentClassElement>();
156  using (new LanguageContext(Project))
157  {
158  var assign = new AttributeAssignment();
159  foreach (var languageVariant in Project.LanguageVariants)
160  {
161  ILanguageVariant targetLanguageVariant =
162  targetCC.Project.LanguageVariants[languageVariant.Abbreviation];
163  foreach (var curElementName in elementNames)
164  {
165  IContentClassElement curTargetContentClassElement;
166  languageVariant.Select();
167  var curSourceContentClassElement = Elements[curElementName];
168  if (createdElements.TryGetValue(curElementName, out curTargetContentClassElement))
169  {
170  targetLanguageVariant.Select();
171  assign.AssignAllRedDotAttributesForLanguage(curSourceContentClassElement,
172  curTargetContentClassElement,
173  targetLanguageVariant.Abbreviation);
174  curTargetContentClassElement.CommitInCurrentLanguage();
175  }
176  else
177  {
178  targetLanguageVariant.Select();
179  curTargetContentClassElement = curSourceContentClassElement.CopyToContentClass(targetCC);
180  createdElements.Add(curElementName, curTargetContentClassElement);
181  }
182  }
183  }
184  }
185  }
186 
192  public void CopyToProject(IProject project, Guid targetFolderGuid)
193  {
194  ContentClass targetCC = CreateCopyInProject(project, targetFolderGuid);
195 
196  CopyProjectVariantAssignmentToCC(targetCC);
197 
198  CopyAttributesToCC(targetCC);
199 
200  CopyAllElementsToCC(targetCC);
201 
202  CopyPreassignedKeywordsToCC(targetCC);
203  }
204 
205  private void CopyProjectVariantAssignmentToCC(ContentClass targetCC)
206  {
207  var x =
208  //ProjectVariantAssignments.ToLookup(x=>targetCC.TemplateVariants.GetByName(x.TemplateVariant.Name),
209  //x=>targetCC.Project.ProjectVariants.GetByName(x.ProjectVariant.Name));
210 
211  ProjectVariantAssignments.ToLookup(
212  assignment => targetCC.TemplateVariants[assignment.TemplateVariant.Name],
213  assignment => new ProjectVariantAssignmentSettings() { ProjectVariant = targetCC.Project.ProjectVariants[assignment.ProjectVariant.Name], IsPublishing = assignment.IsPublishing, IsNotUsingTidy = assignment.IsNotUsingTidy, TemplateVariant = targetCC.TemplateVariants[assignment.TemplateVariant.Name] });
214  targetCC.ProjectVariantAssignments.Assign(x);
215  }
216 
220  public void Delete()
221  {
222  const string DELETE_CC = @"<TEMPLATE action=""delete"" guid=""{0}""/>";
223  XmlDocument xmlDoc = Project.ExecuteRQL(string.Format(DELETE_CC, Guid.ToRQLString()));
224  var template = (XmlElement) xmlDoc.GetElementsByTagName("TEMPLATE")[0];
225  Guid guid;
226  if (template == null || !template.TryGetGuid(out guid) || guid != Guid)
227  {
228  var msgNode = (XmlElement) xmlDoc.GetElementsByTagName("MESSAGE")[0];
229  string msg = "could not delete content class: " + ToString();
230  if (msgNode != null)
231  {
232  msg += "; Reason: " + msgNode.GetAttributeValue("value");
233  }
234  throw new SmartAPIException(Session.ServerLogin, msg);
235  }
236  }
237 
241  [RedDot("description")]
242  public string DescriptionInCurrentDisplayLanguage
243  {
244  get { return GetAttributeValue<string>(); }
245  set { SetAttributeValue(value); }
246  }
247 
253  public IContentClassEditableAreaSettings EditableAreaSettings { get; private set; }
254 
255  public IContentClassElements Elements { get; private set; }
256 
257  public ICollection<IPage> Pages
258  {
259  get { return Project.Pages.Search(x => x.ContentClass = this).ToList(); }
260  }
261 
265  [RedDot("folderguid", ConverterType = typeof (ContentClassFolderConverter), Description = "Content Class Folder"
266  )]
267  public IContentClassFolder Folder
268  {
269  get { return GetAttributeValue<IContentClassFolder>(); }
270  }
271 
272  [RedDot("selectinnewpage")]
273  public bool IsAvailableViaTheShortcutMenuInSmartEdit
274  {
275  get { return GetAttributeValue<bool>(); }
276  set { SetAttributeValue(value); }
277  }
278 
279  [VersionIsGreaterThanOrEqual(9, 0, 0, 41, VersionName = "Version 9 Hotfix 5")]
280  [RedDot("adoptheadlinetoalllanguages")]
281  public bool IsChangingHeadlineEffectiveForAllLanguageVariants
282  {
283  get
284  {
285  VersionVerifier.EnsureVersion(Project.Session);
286  return GetAttributeValue<bool>();
287  }
288  set
289  {
290  VersionVerifier.EnsureVersion(Project.Session);
291  SetAttributeValue(value);
292  }
293  }
294 
295  [RedDot("keywordrequired")]
296  public bool IsKeywordRequired
297  {
298  get { return GetAttributeValue<bool>(); }
299  set { SetAttributeValue(value); }
300  }
301 
302  [RedDot("ignoreglobalworkflow")]
303  public bool IsNotRelevantForGlobalContentWorkflow
304  {
305  get { return GetAttributeValue<bool>(); }
306  set { SetAttributeValue(value); }
307  }
308 
309  public IPageDefinitions PageDefinitions { get; private set; }
310 
314  public IPreassignedKeywords PreassignedKeywords { get; private set; }
315 
319  [RedDot("praefixguid", ConverterType = typeof (SyllableConverter))]
320  public ISyllable Prefix
321  {
322  get { return GetAttributeValue<ISyllable>(); }
323  }
324 
325  public IProjectVariantAssignments ProjectVariantAssignments { get; private set; }
326 
327  [RedDot("requiredcategory", ConverterType = typeof (CategoryConverter))]
328  public ICategory RequiredKeywordCategory
329  {
330  get { return GetAttributeValue<ICategory>(); }
331  set
332  {
333  EnsureInitialization();
334  if (value != null && !IsKeywordRequired)
335  {
336  IsKeywordRequired = true;
337  }
338 
339  SetAttributeValue(value ?? ArbitraryCategory.INSTANCE);
340  }
341  }
342 
346  [RedDot("suffixguid", ConverterType = typeof (SyllableConverter))]
347  public ISyllable Suffix
348  {
349  get { return GetAttributeValue<ISyllable>(); }
350  }
351 
352  public ITemplateVariants TemplateVariants { get; private set; }
353 
354  public override string ToString()
355  {
356  return Name + " (" + Guid.ToRQLString() + ")";
357  }
358 
362  public IContentClassVersions Versions { get; private set; }
363 
364  protected override void LoadWholeObject()
365  {
366  }
367 
368  protected override XmlElement RetrieveWholeObject()
369  {
370  const string LOAD_CC = @"<PROJECT><TEMPLATE action=""load"" guid=""{0}""/></PROJECT>";
371  XmlDocument xmlDoc = Project.ExecuteRQL(string.Format(LOAD_CC, Guid.ToRQLString()));
372  XmlNodeList xmlNodes = xmlDoc.GetElementsByTagName("TEMPLATE");
373  if (xmlNodes.Count != 1)
374  {
375  throw new ArgumentException(String.Format("Could not find content class with guid {0}.",
376  Guid.ToRQLString()));
377  }
378  return (XmlElement) xmlNodes[0];
379  }
380 
381  private void AddProjectVariants(IProject project, XmlElement template)
382  {
383  XmlElement projectVariants = template.AddElement("PROJECTVARIANTS");
384  projectVariants.AddAttribute("action", "assign");
385  foreach (IProjectVariant curVariant in Project.ProjectVariants)
386  {
387  XmlElement projectVariant = projectVariants.AddElement("PROJECTVARIANT");
388  IProjectVariant otherVariant;
389  if (!project.ProjectVariants.TryGetByName(curVariant.Name, out otherVariant))
390  {
391  throw new SmartAPIException(Session.ServerLogin,
392  string.Format("Could not find project variant {0} in project {1}",
393  curVariant.Name, project.Name));
394  }
395  projectVariant.AddAttribute("guid", otherVariant.Guid.ToRQLString());
396  }
397  }
398 
399  private void AddTemplateDescriptions(IProject project, XmlElement template)
400  {
401  XmlElement templateDescriptions = template.AddElement("TEMPLATEDESCRIPTIONS");
402  foreach (ILanguageVariant languageVariant in project.LanguageVariants)
403  {
404  XmlElement templateDescription = templateDescriptions.AddElement("TEMPLATEDESCRIPTION");
405  templateDescription.AddAttribute("dialoglanguageid", languageVariant.Abbreviation);
406  templateDescription.AddAttribute("name", Name);
407  if (!string.IsNullOrEmpty(DescriptionInCurrentDisplayLanguage))
408  {
409  templateDescription.AddAttribute("description", DescriptionInCurrentDisplayLanguage);
410  }
411  }
412  }
413 
414  private void AddTemplateVariants(XmlElement template)
415  {
416  XmlDocument ownerDocument = template.OwnerDocument;
417 
418  XmlElement templateVariants = template.AddElement("TEMPLATEVARIANTS");
419  foreach (ITemplateVariant curTemplateVariant in TemplateVariants)
420  {
421  XmlElement templateVariant = templateVariants.AddElement("TEMPLATEVARIANT");
422  templateVariant.AddAttribute("name", curTemplateVariant.Name);
423  // ReSharper disable PossibleNullReferenceException
424  XmlText textNode = ownerDocument.CreateTextNode(curTemplateVariant.Data);
425  // ReSharper restore PossibleNullReferenceException
426  templateVariant.AppendChild(textNode);
427  }
428  }
429 
430  private void CopyAllElementsToCC(IContentClass targetCC)
431  {
432  CopyElementsToContentClass(targetCC, Elements.Select(element => element.Name).ToArray());
433  }
434 
435  private void CopyAttributesToCC(IContentClass targetCC)
436  {
437  var assignment = new AttributeAssignment();
438  assignment.AssignAllLanguageIndependentRedDotAttributes(EditableAreaSettings, targetCC.EditableAreaSettings);
439 
440  targetCC.EditableAreaSettings.Commit();
441  targetCC.Refresh();
442  try
443  {
444  assignment.AssignAllLanguageIndependentRedDotAttributes(this, targetCC);
445  } catch (AttributeChangeException e)
446  {
447  throw new SmartAPIException(Session.ServerLogin,
448  string.Format(
449  "Unable to assign attribute {0} in content class {1} of project {2} to content class {3} of project {4}",
450  e.AttributeName, Name, Project.Name, targetCC.Name,
451  targetCC.Project.Name), e);
452  }
453  targetCC.Commit();
454  }
455 
456  private void CopyPreassignedKeywordsToCC(IContentClass targetCC)
457  {
458  try
459  {
460  List<IKeyword> keywordsToAssign =
461  PreassignedKeywords.Select(
462  x => targetCC.Project.Categories.GetByName(x.Category.Name).Keywords.GetByName(x.Name)).ToList();
463  targetCC.PreassignedKeywords.Set(keywordsToAssign);
464  } catch (Exception e)
465  {
466  throw new SmartAPIException(Session.ServerLogin,
467  string.Format("Could not copy preassigned keywords for content class {0}",
468  Name), e);
469  }
470  }
471 
472  private ContentClass CreateContentClass(IProject project, XmlElement template)
473  {
474  XmlDocument creationResultNode = project.ExecuteRQL(template.NodeToString());
475  XmlNode guidTextNode = creationResultNode.FirstChild;
476  Guid newCCGuid;
477  if (guidTextNode == null || guidTextNode.NodeType != XmlNodeType.Element || guidTextNode.FirstChild == null ||
478  !Guid.TryParse(guidTextNode.FirstChild.Value.Trim(), out newCCGuid))
479  {
480  throw new SmartAPIException(Session.ServerLogin,
481  string.Format("Could not create content class '{0}'", Name));
482  }
483 
484  var targetCC = new ContentClass(project, newCCGuid);
485  return targetCC;
486  }
487 
488  private ContentClass CreateCopyInProject(IProject project, Guid targetFolderGuid)
489  {
490  IContentClassFolder folder = project.ContentClassFolders.GetByGuid(targetFolderGuid);
491  if (folder == null)
492  {
493  throw new ArgumentException("no such content class folder '" + targetFolderGuid.ToRQLString() +
494  "' in project " + Name);
495  }
496 
497  var xmlDoc = new XmlDocument();
498  XmlElement template = CreateTemplateXmlElement(xmlDoc, folder);
499 
500  AddTemplateDescriptions(project, template);
501 
502  AddTemplateVariants(template);
503 
504  //AddProjectVariants(project, template);
505 
506  return CreateContentClass(project, template);
507  }
508 
509  private static XmlElement CreateTemplateXmlElement(XmlDocument xmlDoc, IContentClassFolder folder)
510  {
511  XmlElement template = xmlDoc.AddElement("TEMPLATE");
512  template.AddAttribute("action", "addnew");
513  template.AddAttribute("folderguid", folder.Guid.ToRQLString());
514  return template;
515  }
516 
517  private void Init()
518  {
519  Versions = new ContentClassVersions(this, Caching.Enabled);
520  PreassignedKeywords = new PreassignedKeywords(this, Caching.Enabled);
521  PageDefinitions = new PageDefinitions(this, Caching.Enabled);
522  TemplateVariants = new TemplateVariants(this, Caching.Enabled);
523  Elements = new ContentClassElements(this, Caching.Enabled);
524  ProjectVariantAssignments = new ProjectVariantAssignments(this, Caching.Enabled);
525  EditableAreaSettings = new CCEditableAreaSettings(this);
526  }
527 
531  internal class ContentClassVersion : RedDotProjectObject, IContentClassVersion
532  {
533  private DateTime? _date;
534  private IContentClassFolder _folder;
535  private IUser _user;
536 
537  internal ContentClassVersion(IContentClass parent, XmlElement xmlElement) : base(parent.Project, xmlElement)
538  {
539  ContentClass = parent;
540  }
541 
542  public IContentClass ContentClass { get; private set; }
543 
544  public ContentClassVersionType CreationType
545  {
546  get { return XmlElement.GetAttributeValue("type").ToEnum<ContentClassVersionType>(); }
547  }
548 
552  public DateTime Date
553  {
554  get { return _date ?? (_date = XmlElement.GetOADate()).GetValueOrDefault(); }
555  }
556 
560  public string DescriptionInCurrentDisplayLanguage
561  {
562  get { return XmlElement.GetAttributeValue("description"); }
563  }
564 
565  public IContentClassFolder Folder
566  {
567  get { return _folder ?? (_folder = Project.ContentClassFolders.GetByGuid(XmlElement.GetGuid("folderguid"))); }
568  }
569 
570  public IUser User
571  {
572  get
573  {
574  if (_user != null)
575  {
576  return _user;
577  }
578  string userGuid = XmlElement.GetAttributeValue("userguid");
579  return string.IsNullOrEmpty(userGuid)
580  ? null
581  : _user =
582  ContentClass.Project.Session.ServerManager.Users.GetByGuid(GuidConvert(userGuid));
583  }
584  }
585 
586  public string Username
587  {
588  get { return XmlElement.GetAttributeValue("username"); }
589  }
590  }
591 
594  ILanguageDependentXmlBasedObject
595  {
596  }
597  }
598 
600  {
601  AutomaticallyCreated = 1,
602  ManuallyCreate = 2,
603  Temporary = 3
604  }
605 }