/// <inheritdoc />
    public override Topic Load(int topicId, bool isRecursive = true) {

      /*------------------------------------------------------------------------------------------------------------------------
      | Establish database connection
      \-----------------------------------------------------------------------------------------------------------------------*/
      var topic                 = (Topic?)null;

      using var connection      = new SqlConnection(_connectionString);
      using var command         = new SqlCommand("GetTopics", connection) {
        CommandType             = CommandType.StoredProcedure,
        CommandTimeout          = 120
      };

      /*------------------------------------------------------------------------------------------------------------------------
      | Establish query parameters
      \-----------------------------------------------------------------------------------------------------------------------*/
      command.AddParameter("TopicID", topicId);
      command.AddParameter("DeepLoad", isRecursive);

      /*------------------------------------------------------------------------------------------------------------------------
      | Process database query
      \-----------------------------------------------------------------------------------------------------------------------*/
      try {
        connection.Open();
        using var reader        = command.ExecuteReader();
        topic                   = reader.LoadTopicGraph();
      }

      /*------------------------------------------------------------------------------------------------------------------------
      | Catch exception
      \-----------------------------------------------------------------------------------------------------------------------*/
      catch (SqlException exception) {
        throw new TopicRepositoryException($"Topics failed to load: '{exception.Message}'", exception);
      }

      /*------------------------------------------------------------------------------------------------------------------------
      | Validate results
      \-----------------------------------------------------------------------------------------------------------------------*/
      if (topic is null) {
        if (topicId == -1) {
          topic = TopicFactory.Create("Root", "Container");
        }
        else {
          throw new TopicNotFoundException(topicId);
        }
      }

      /*------------------------------------------------------------------------------------------------------------------------
      | Establish content type cache
      >-------------------------------------------------------------------------------------------------------------------------
      | If this load represents the entire topic graph, then relay the content type configuration to the TopicRepositoryBase in
      | order to either update or establish the content type cache. Not only does this prevent the need for a separate redundant
      | call later but, even more importantly, it helps ensure the same object references are maintained so that any updates to
      | subsequently cached content types are available.
      \-----------------------------------------------------------------------------------------------------------------------*/
      base.SetContentTypeDescriptors(topic);

      /*------------------------------------------------------------------------------------------------------------------------
      | Return objects
      \-----------------------------------------------------------------------------------------------------------------------*/
      return topic;

    }
예제 #2
0
 public void SetValue_CorrectValue_IsReturned() {
   var topic = TopicFactory.Create("Test", "Container");
   topic.Attributes.SetValue("Foo", "Bar");
   Assert.AreEqual<string>("Bar", topic.Attributes.GetValue("Foo"));
 }
예제 #3
0
 public void Create_ContentType_ReturnsDerivedTopic() {
   var topic = TopicFactory.Create("Test", "ContentTypeDescriptor");
   Assert.IsNotNull(topic);
   Assert.IsInstanceOfType(topic, typeof(ContentTypeDescriptor));
 }
예제 #4
0
 public void Create_ReturnsTopic() {
   var topic = TopicFactory.Create("Test", "Page");
   Assert.IsNotNull(topic);
   Assert.AreEqual<string>(topic.Key, "Test");
   Assert.AreEqual<string>(topic.Attributes.GetValue("ContentType"), "Page");
 }
예제 #5
0
    /*==========================================================================================================================
    | METHOD: CREATE FAKE DATA
    \-------------------------------------------------------------------------------------------------------------------------*/
    /// <summary>
    ///   Creates a collection of fake data that loosely mimics a bare bones database.
    /// </summary>
    private Topic CreateFakeData() {

      /*------------------------------------------------------------------------------------------------------------------------
      | Establish root
      \-----------------------------------------------------------------------------------------------------------------------*/
      var rootTopic = TopicFactory.Create("Root", "Container", 900);
      var currentAttributeId = 800;

      /*------------------------------------------------------------------------------------------------------------------------
      | Establish configuration
      \-----------------------------------------------------------------------------------------------------------------------*/
      var configuration = TopicFactory.Create("Configuration", "Container", rootTopic);
      var contentTypes = TopicFactory.Create("ContentTypes", "ContentTypeDescriptor", configuration);

      addAttribute(contentTypes, "Key", "TextAttribute", false, true);
      addAttribute(contentTypes, "ContentType", "TextAttribute", false, true);
      addAttribute(contentTypes, "Title", "TextAttribute", true, true);
      addAttribute(contentTypes, "TopicId", "TopicReferenceAttribute", false);

      var contentTypeDescriptor = TopicFactory.Create("ContentTypeDescriptor", "ContentTypeDescriptor", contentTypes);

      addAttribute(contentTypeDescriptor, "ContentTypes", "RelationshipAttribute");
      addAttribute(contentTypeDescriptor, "Attributes", "NestedTopicListAttribute");

      TopicFactory.Create("Container", "ContentTypeDescriptor", contentTypes);
      TopicFactory.Create("Lookup", "ContentTypeDescriptor", contentTypes);
      TopicFactory.Create("LookupListItem", "ContentTypeDescriptor", contentTypes);
      TopicFactory.Create("List", "ContentTypeDescriptor", contentTypes);

      var attributeDescriptor = (ContentTypeDescriptor)TopicFactory.Create("AttributeDescriptor", "ContentTypeDescriptor", contentTypes);

      addAttribute(attributeDescriptor, "DefaultValue", "TextAttribute", false, true);
      addAttribute(attributeDescriptor, "IsRequired", "TextAttribute", false, true);

      TopicFactory.Create("BooleanAttribute", "ContentTypeDescriptor", attributeDescriptor);
      TopicFactory.Create("NestedTopicListAttribute", "ContentTypeDescriptor", attributeDescriptor);
      TopicFactory.Create("NumberAttribute", "ContentTypeDescriptor", attributeDescriptor);
      TopicFactory.Create("RelationshipAttribute", "ContentTypeDescriptor", attributeDescriptor);
      TopicFactory.Create("TextAttribute", "ContentTypeDescriptor", attributeDescriptor);
      TopicFactory.Create("TopicReferenceAttribute", "ContentTypeDescriptor", attributeDescriptor);

      var pageContentType = TopicFactory.Create("Page", "ContentTypeDescriptor", contentTypes);

      addAttribute(pageContentType, "MetaTitle");
      addAttribute(pageContentType, "MetaDescription");
      addAttribute(pageContentType, "IsHidden", "TextAttribute", false);
      addAttribute(pageContentType, "TopicReference", "TopicReferenceAttribute", false);

      pageContentType.Relationships.SetTopic("ContentTypes", pageContentType);
      pageContentType.Relationships.SetTopic("ContentTypes", contentTypeDescriptor);

      var contactContentType = TopicFactory.Create("Contact", "ContentTypeDescriptor", contentTypes);

      addAttribute(contactContentType, "Name", isExtended: false);
      addAttribute(contactContentType, "AlternateEmail", isExtended: false);
      addAttribute(contactContentType, "BillingContactEmail", isExtended: false);

      /*------------------------------------------------------------------------------------------------------------------------
      | Local addAttribute() helper function
      \-----------------------------------------------------------------------------------------------------------------------*/
      AttributeDescriptor addAttribute(
        Topic contentType,
        string attributeKey,
        string editorType       = "TextAttribute",
        bool isExtended         = true,
        bool isRequired         = false
      ) {
        var container = contentType.Children.GetTopic("Attributes");
        if (container is null) {
          container = TopicFactory.Create("Attributes", "List", contentType);
          container.Attributes.SetBoolean("IsHidden", true);
        }
        var attribute = (AttributeDescriptor)TopicFactory.Create(attributeKey, editorType, currentAttributeId++, container);
        attribute.IsRequired = isRequired;
        attribute.IsExtendedAttribute = isExtended;
        return attribute;
      }

      /*------------------------------------------------------------------------------------------------------------------------
      | Establish metadata
      \-----------------------------------------------------------------------------------------------------------------------*/
      var metadata = TopicFactory.Create("Metadata", "Container", configuration);
      var categories = TopicFactory.Create("Categories", "Lookup", metadata);
      var lookup = TopicFactory.Create("LookupList", "List", categories);

      for (var i=1; i<=5; i++) {
        TopicFactory.Create("Category" + i, "LookupListItem", lookup);
      }

      /*------------------------------------------------------------------------------------------------------------------------
      | Establish content
      \-----------------------------------------------------------------------------------------------------------------------*/
      var web = TopicFactory.Create("Web", "Page", 10000, rootTopic);

      CreateFakeData(web, 2, 3);

      var pageGroup = TopicFactory.Create("Web_3", "PageGroup", web);

      TopicFactory.Create("Web_3_0", "Page", pageGroup);
      TopicFactory.Create("Web_3_1", "Page", pageGroup);

      /*------------------------------------------------------------------------------------------------------------------------
      | Set to cache
      \-----------------------------------------------------------------------------------------------------------------------*/
      return rootTopic;

    }
예제 #6
0
    /*==========================================================================================================================
    | METHOD: INVOKE
    \-------------------------------------------------------------------------------------------------------------------------*/
    /// <summary>
    ///   Assembles the view model for the <see cref="TopicListViewComponent"/>.
    /// </summary>
    public IViewComponentResult Invoke(
      EditingTopicViewModel currentTopic,
      TopicListAttributeDescriptorViewModel attribute,
      string? htmlFieldPrefix = null
    ) {

      /*------------------------------------------------------------------------------------------------------------------------
      | Validate parameters
      \-----------------------------------------------------------------------------------------------------------------------*/
      Contract.Requires(currentTopic, nameof(currentTopic));
      Contract.Requires(attribute, nameof(attribute));
      Contract.Requires(currentTopic.ContentType, nameof(currentTopic.ContentType));
      Contract.Requires(attribute.Key, nameof(attribute.Key));

      /*------------------------------------------------------------------------------------------------------------------------
      | Set HTML prefix
      \-----------------------------------------------------------------------------------------------------------------------*/
      ViewData.TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix;

      /*------------------------------------------------------------------------------------------------------------------------
      | Establish view model
      \-----------------------------------------------------------------------------------------------------------------------*/
      var viewModel = new TopicListAttributeViewModel(currentTopic, attribute);

      /*------------------------------------------------------------------------------------------------------------------------
      | Set default value
      \-----------------------------------------------------------------------------------------------------------------------*/
      var defaultValue = currentTopic.Attributes.ContainsKey(attribute.Key)? currentTopic.Attributes[attribute.Key] : null;

      /*------------------------------------------------------------------------------------------------------------------------
      | Get root topic
      \-----------------------------------------------------------------------------------------------------------------------*/
      var rootTopic             = (Topic?)null;

      if (attribute.RelativeTopicBase is not null) {
        var baseTopic             = _topicRepository.Load(currentTopic.UniqueKey);
        Contract.Assume(baseTopic, $"The topic with the key '{currentTopic.UniqueKey}' could not be located.");
        if (String.IsNullOrEmpty(currentTopic.Key)) {
          baseTopic               = TopicFactory.Create("NewTopic", currentTopic.ContentType, baseTopic);
          baseTopic.Parent?.Children.Remove(baseTopic);
        }
        rootTopic                 = attribute.RelativeTopicBase switch {
          "CurrentTopic"          => baseTopic,
          "ParentTopic"           => baseTopic.Parent,
          "GrandparentTopic"      => (Topic?)baseTopic.Parent?.Parent,
          "ContentTypeDescriptor" => (Topic?)_topicRepository.GetContentTypeDescriptors().FirstOrDefault(t => t.Key.Equals(baseTopic.ContentType, StringComparison.Ordinal)),
          _ => baseTopic
        };
      }
      else if (attribute.RootTopic is not null) {
        rootTopic = _topicRepository.Load(attribute.RootTopic.UniqueKey);
      }

      if (rootTopic is not null && !String.IsNullOrEmpty(attribute.RelativeTopicPath)) {
        rootTopic = rootTopic.GetByUniqueKey(rootTopic.GetUniqueKey() + ":" + attribute.RelativeTopicPath);
      }

      /*------------------------------------------------------------------------------------------------------------------------
      | Get values
      \-----------------------------------------------------------------------------------------------------------------------*/
      var topics = GetTopics(
        rootTopic,
        attribute.AttributeKey,
        attribute.AttributeValue
      );

      /*------------------------------------------------------------------------------------------------------------------------
      | Set label
      \-----------------------------------------------------------------------------------------------------------------------*/
      if (!String.IsNullOrEmpty(viewModel.InheritedValue)) {
        setLabel(viewModel.InheritedValue, "inherited value");
      }
      else if (!String.IsNullOrEmpty(viewModel.AttributeDescriptor.DefaultValue)) {
        setLabel(viewModel.AttributeDescriptor.DefaultValue, "default value");
      }
      else if (!String.IsNullOrEmpty(viewModel.AttributeDescriptor.ImplicitValue)) {
        setLabel(viewModel.AttributeDescriptor.ImplicitValue, "implicit default");
      }
      else {
        setLabel(attribute.DefaultLabel?? "Select an option…");
      }

      /*------------------------------------------------------------------------------------------------------------------------
      | Get values from repository
      \-----------------------------------------------------------------------------------------------------------------------*/
      foreach (var topic in topics) {

        var title = viewModel.TopicList.Any(t => t.Text == topic.Title)? $"{topic.Title} ({topic.Key})" : topic.Title;
        var value = getValue(topic);

        viewModel.TopicList.Add(
          new() {
            Value = value,
            Text = title,
            Selected = value == defaultValue
          }
        );

      }

      /*------------------------------------------------------------------------------------------------------------------------
      | Return view with view model
      \-----------------------------------------------------------------------------------------------------------------------*/
      return View(viewModel);

      /*------------------------------------------------------------------------------------------------------------------------
      | Function: Get Value
      \-----------------------------------------------------------------------------------------------------------------------*/
      string getValue(QueryResultTopicViewModel topic) => ReplaceTokens(topic, "{" + attribute.ValueProperty + "}");

      /*------------------------------------------------------------------------------------------------------------------------
      | Function: Set Label
      \-----------------------------------------------------------------------------------------------------------------------*/
      void setLabel(string value, string? contextualLabel = null) {
        var inheritedTopic = topics.Where(t => t.Key == value).FirstOrDefault();
        var label = inheritedTopic?.Title ?? value;
        if (contextualLabel is not null) {
          label += " (" + contextualLabel + ")";
        }
        viewModel?.TopicList.Add(
          new() {
            Value = "",
            Text = label
          }
        );
      }

    }
예제 #7
0
        public void DrinkTopicFactory_Create_DrinkTopic()
        {
            Topic expected = _topicFactory.Create(A.Dummy <SimpleDrink>(), A.Dummy <TopicInfo>());

            Assert.NotNull(expected);
        }