public void ParseDeprecated() { string[] comments = { "# Summary", "This is some text", "# Deprecated", "Some other text" }; string dep = "NewName"; string warning = "> [!WARNING]\n> Deprecated\n"; string warningText = "name has been deprecated. Please use @\"newname\" instead."; // Test with just the Deprecated comment section var dc = new DocComment(comments); Assert.Equal(comments[1] + "\r" + warning + "\r" + comments[3], dc.Summary); Assert.Equal(warning + "\r" + comments[3], dc.ShortSummary); Assert.Equal(comments[3], dc.Documentation); // Test with just the deprecated attribute dc = new DocComment(comments.Take(2), "name", true, dep); Assert.Equal(comments[1] + "\r" + warning + "\r" + warningText, dc.Summary); Assert.Equal(warning + "\r" + warningText, dc.ShortSummary); Assert.Equal(warningText, dc.Documentation); // Test with both dc = new DocComment(comments, "name", true, dep); Assert.Equal(comments[1] + "\r" + warning + "\r" + warningText + "\r" + comments[3], dc.Summary); Assert.Equal(warning + "\r" + warningText, dc.ShortSummary); Assert.Equal(warningText, dc.Documentation); }
public override QsCallable OnCallableDeclaration(QsCallable callable) { callable = base.OnCallableDeclaration(callable); // If the callable didn't come from a Q# source file, then it // came in from a reference, and shouldn't be documented in this // project. if (!callable.IsInCompilationUnit()) { return(callable); } var isDeprecated = callable.IsDeprecated(out var replacement); var docComment = new DocComment( callable.Documentation, callable.FullName.Name, deprecated: isDeprecated, replacement: replacement ); var callableName = $"{callable.FullName.Namespace}.{callable.FullName.Name}"; // Validate input and type parameter names. var inputDeclarations = callable.ArgumentTuple.ToDictionaryOfDeclarations(); this.ValidateNames( callableName, "input", name => inputDeclarations.ContainsKey(name), docComment.Input.Keys, range: null, // TODO: provide more exact locations once supported by DocParser. source: callable.SourceFile ); this.ValidateNames( callableName, "type parameter", name => callable.Signature.TypeParameters.Any( typeParam => typeParam is QsLocalSymbol.ValidName validName && validName.Item == name.TrimStart('\'') ), docComment.TypeParameters.Keys, range: null, // TODO: provide more exact locations once supported by DocParser. source: callable.SourceFile ); this.writer?.WriteOutput(callable, docComment)?.Wait(); return(callable .AttributeBuilder() .MaybeWithSimpleDocumentationAttribute("Summary", docComment.Summary) .MaybeWithSimpleDocumentationAttribute("Description", docComment.Description) .MaybeWithSimpleDocumentationAttribute("Remarks", docComment.Remarks) .MaybeWithSimpleDocumentationAttribute("References", docComment.References) .WithListOfDocumentationAttributes("SeeAlso", docComment.SeeAlso) .WithListOfDocumentationAttributes("Example", docComment.Examples) .WithDocumentationAttributesFromDictionary("Input", docComment.Input) .MaybeWithSimpleDocumentationAttribute("Output", docComment.Output) .WithDocumentationAttributesFromDictionary("TypeParameter", docComment.TypeParameters) .Build()); }
public async Task <IViewComponentResult> InvokeAsync(Doc entity, DocComment reply) { // Populate previous and next entity var model = await GetModelAsync(entity); // Return view return(View(model)); }
public void DocCommentAccessibleObject_Ctor_Default() { using PropertyGrid propertyGrid = new PropertyGrid(); using DocComment docComment = new DocComment(propertyGrid); DocCommentAccessibleObject accessibleObject = new DocCommentAccessibleObject(docComment, propertyGrid); Assert.Equal(docComment, accessibleObject.Owner); Assert.False(propertyGrid.IsHandleCreated); Assert.False(docComment.IsHandleCreated); }
public void DocCommentAccessibleObject_ControlType_IsPane_IfAccessibleRoleIsDefault() { using PropertyGrid propertyGrid = new PropertyGrid(); using DocComment docComment = new DocComment(propertyGrid); // AccessibleRole is not set = Default object actual = docComment.AccessibilityObject.GetPropertyValue(UiaCore.UIA.ControlTypePropertyId); Assert.Equal(UiaCore.UIA.PaneControlTypeId, actual); Assert.False(propertyGrid.IsHandleCreated); Assert.False(docComment.IsHandleCreated); }
public void ParseDocComments() { string[] comments = { "# Summary", "Encodes a multi-qubit Pauli operator represented as an array of", "single-qubit Pauli operators into an integer.", "", "Test second paragraph.", "", "# Description", "This is some text", "", "This is some more text", "", "# Input", "## paulies", "An array of at most 31 single-qubit Pauli operators.", "", "# Output", "An integer uniquely identifying `paulies`, as described below.", "", "# Remarks", "Each Pauli operator can be encoded using two bits:", "$$", "\\begin{align}", "\\boldone \\mapsto 00, \\quad X \\mapsto 01, \\quad Y \\mapsto 11,", "\\quad Z \\mapsto 10.", "\\end{align}", "$$", "", "Given an array of Pauli operators `[P0, ..., Pn]`, this function returns an", "integer with binary expansion formed by concatenating", "the mappings of each Pauli operator in big-endian order", "`bits(Pn) ... bits(P0)`." }; var dc = new DocComment(comments); Assert.Equal(comments[1] + "\r" + comments[2] + "\r" + comments[3] + "\r" + comments[4], dc.Summary); Assert.Equal(comments[1] + "\r" + comments[2], dc.ShortSummary); Assert.Equal(comments[1] + "\r" + comments[2], dc.FullSummary); Assert.Equal(comments[1] + "\r" + comments[2] + "\r" + comments[3] + "\r" + comments[4] + "\r" + comments[5] + "\r" + comments[7] + "\r" + comments[8] + "\r" + comments[9], dc.Documentation); Assert.Single(dc.Input); Assert.Equal(comments[13], dc.Input["paulies"]); Assert.Equal(comments[16], dc.Output); Assert.Empty(dc.TypeParameters); #pragma warning disable 618 // Example is obsolete. Assert.Equal("", dc.Example); #pragma warning restore 618 var remarks = string.Join("\r", comments.AsSpan(19, 12).ToArray()); Assert.Equal(remarks, dc.Remarks); }
public override QsNamespace OnNamespace(QsNamespace ns) { ns = base.OnNamespace(ns); if (ns.Elements.Any(element => element.IsInCompilationUnit())) { // Concatenate everything into one documentation comment. var comment = new DocComment( ns.Documentation.SelectMany(group => group).SelectMany(comments => comments)); if (ns.Elements.Any(element => element switch { QsNamespaceElement.QsCallable { Item: var callable } => callable.Access.IsPublic,
public override QsNamespace OnNamespace(QsNamespace ns) { ns = base.OnNamespace(ns); if (ns.Elements.Any(element => element.IsInCompilationUnit())) { // Concatenate everything into one documentation comment. var comment = new DocComment( ns.Documentation.SelectMany(group => group).SelectMany(comments => comments) ); writer?.WriteOutput(ns, comment)?.Wait(); } return(ns); }
public async Task <IActionResult> SendFile(DocComment doc) { foreach (var uploadedFile in doc.files) { var name = uploadedFile.FileName; var path = "/docs/" + name; using (var fileStream = new FileStream(AppSettings.WebRootPath + path, FileMode.Create)) { await uploadedFile.CopyToAsync(fileStream); } } return(Ok(new { message = "Idi naxyi" })); }
public void DocCommentAccessibleObject_Role_IsExpected_ByDefault(bool createControl, AccessibleRole expectedRole) { using PropertyGrid propertyGrid = new PropertyGrid(); using DocComment docComment = new DocComment(propertyGrid); // AccessibleRole is not set = Default if (createControl) { docComment.CreateControl(); } AccessibleRole actual = docComment.AccessibilityObject.Role; Assert.Equal(expectedRole, actual); Assert.False(propertyGrid.IsHandleCreated); Assert.Equal(createControl, docComment.IsHandleCreated); }
public override QsCustomType OnTypeDeclaration(QsCustomType type) { type = base.OnTypeDeclaration(type); // If the UDT didn't come from a Q# source file, then it // came in from a reference, and shouldn't be documented in this // project. if (!type.IsInCompilationUnit()) { return(type); } var isDeprecated = type.IsDeprecated(out var replacement); var docComment = new DocComment( type.Documentation, type.FullName.Name, deprecated: isDeprecated, replacement: replacement ); // Validate named item names. var inputDeclarations = type.TypeItems.ToDictionaryOfDeclarations(); this.ValidateNames( $"{type.FullName.Namespace}.{type.FullName.Name}", "named item", name => inputDeclarations.ContainsKey(name), docComment.Input.Keys, range: null, // TODO: provide more exact locations once supported by DocParser. source: type.SourceFile ); this.writer?.WriteOutput(type, docComment)?.Wait(); return(type .AttributeBuilder() .MaybeWithSimpleDocumentationAttribute("Summary", docComment.Summary) .MaybeWithSimpleDocumentationAttribute("Description", docComment.Description) .MaybeWithSimpleDocumentationAttribute("Remarks", docComment.Remarks) .MaybeWithSimpleDocumentationAttribute("References", docComment.References) .WithListOfDocumentationAttributes("SeeAlso", docComment.SeeAlso) .WithListOfDocumentationAttributes("Example", docComment.Examples) .WithDocumentationAttributesFromDictionary("NamedItem", docComment.NamedItems) .Build()); }
public async Task <IViewComponentResult> InvokeAsync(Doc entity, DocComment reply) { // We always need a entity to display tags if (entity == null) { throw new ArgumentNullException(nameof(entity)); } // Get tags and return view var tags = await _tagStore.GetByEntityIdAsync(entity.Id); return(View(new TagListViewModel() { Topic = entity, Reply = reply, Tags = tags? .Where(t => t.EntityReplyId == (reply?.Id ?? 0)) .OrderByDescending(t => t.TotalEntities) })); }
/// <summary> /// Given a documentation comment describing a Q# namespace, /// writes a Markdown file documenting that namespace to /// <see cref="OutputPath" />. /// </summary> /// <param name="ns">The Q# namespace being documented.</param> /// <param name="docComment"> /// The API documentation comment describing <paramref name="ns" />. /// </param> /// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns> public async Task WriteOutput(QsNamespace ns, DocComment docComment) { var name = ns.Name; var uid = name; var title = $"{name} namespace"; var header = new Dictionary <string, object> { // DocFX metadata ["uid"] = name, ["title"] = title, // docs.ms metadata ["ms.date"] = DateTime.Today.ToString(), ["ms.topic"] = "managed-reference", // Q# metadata ["qsharp.kind"] = "namespace", ["qsharp.name"] = name, ["qsharp.summary"] = docComment.Summary, }; var document = $@" # {title} {docComment.Summary} " .MaybeWithSection("Description", docComment.Description) .WithSectionForEach("Example", docComment.Examples) .MaybeWithSection( "See Also", string.Join("\n", docComment.SeeAlso.Select( seeAlso => AsSeeAlsoLink(seeAlso) )) ) .WithYamlHeader(header); // Open a file to write the new doc to. await this.WriteAllTextAsync( $"{name}.md", document ); }
async Task <ICommandResultBase> ResetEditDetails(Doc entity, DocComment reply, IUser user) { var result = new CommandResultBase(); // We need to be authenticated to make changes if (user == null) { return(result.Success()); } if (reply != null) { reply.ModifiedUserId = user.Id; reply.ModifiedDate = DateTimeOffset.UtcNow; reply.EditedUserId = 0; reply.EditedDate = null; var updateResult = await _entityReplyStore.UpdateAsync(reply); if (updateResult != null) { return(result.Success()); } } else { entity.ModifiedUserId = user.Id; entity.ModifiedDate = DateTimeOffset.UtcNow; entity.EditedUserId = 0; entity.EditedDate = null; var updateResult = await _entityStore.UpdateAsync(entity); if (updateResult != null) { return(result.Success()); } } return(result.Success()); }
public async Task <IActionResult> Rollback(int id) { // Validate if (id <= 0) { throw new ArgumentOutOfRangeException(nameof(id)); } // Get history point var history = await _entityHistoryStore.GetByIdAsync(id); // Ensure we found the history point if (history == null) { return(NotFound()); } // Get entity for history point var entity = await _entityStore.GetByIdAsync(history.EntityId); // Ensure we found the entity if (entity == null) { return(NotFound()); } // Get reply DocComment reply = null; if (history.EntityReplyId > 0) { reply = await _entityReplyStore.GetByIdAsync(history.EntityReplyId); // Ensure we found a reply if supplied if (reply == null) { return(NotFound()); } } // Get current user var user = await _contextFacade.GetAuthenticatedUserAsync(); // We always need to be logged in to edit entities if (user == null) { return(Unauthorized()); } // Ensure we have permission if (!await _authorizationService.AuthorizeAsync(HttpContext.User, entity.CategoryId, reply != null ? Permissions.RevertReplyHistory : Permissions.RevertEntityHistory)) { return(Unauthorized()); } ICommandResultBase result; if (reply != null) { // Only update edited information if the message changes if (history.Message != reply.Message) { reply.Message = history.Message; reply.EditedUserId = user?.Id ?? 0; reply.EditedDate = DateTimeOffset.UtcNow; } // Update reply to history point result = await _entityReplyManager.UpdateAsync(reply); } else { // Only update edited information if the message changes if (history.Message != entity.Message) { entity.Message = history.Message; entity.EditedUserId = user?.Id ?? 0; entity.EditedDate = DateTimeOffset.UtcNow; } // Update entity to history point result = await _entityManager.UpdateAsync(entity); } // Add result if (result.Succeeded) { _alerter.Success(T["Version Rolled Back Successfully!"]); } else { foreach (var error in result.Errors) { _alerter.Danger(T[error.Description]); } } // Redirect return(Redirect(_contextFacade.GetRouteUrl(new RouteValueDictionary() { ["area"] = "Plato.Docs", ["controller"] = "Home", ["action"] = "Reply", ["opts.id"] = entity.Id, ["opts.alias"] = entity.Alias, ["opts.replyId"] = reply?.Id ?? 0 }))); }
public async Task UpdateAsync(int categoryId) { // Get supplied category and all parent categories var parents = await _channelStore.GetParentsByIdAsync(categoryId); // Update details within current and all parents foreach (var parent in parents) { // Get all children for current category var children = await _channelStore.GetChildrenByIdAsync(parent.Id); // Get latest topic & total topic count for current channel var topics = await _topicStore.QueryAsync() .Take(1, 1) // we only need the latest topic .Select <EntityQueryParams>(q => { // Include entities from child channels? if (children != null) { var channelIds = children .Select(c => c.Id) .Append(parent.Id) .ToArray(); q.CategoryId.IsIn(channelIds); } else { // Get topics for current channel q.CategoryId.Equals(parent.Id); } q.HidePrivate.True(); q.HideHidden.True(); q.HideSpam.True(); q.HideDeleted.True(); }) .OrderBy("LastReplyDate", OrderBy.Desc) .ToList(); // Get latest reply & total reply count for current channel var replies = await _replyStore.QueryAsync() .Take(1, 1) // we only need the latest reply .Select <EntityReplyQueryParams>(q => { // Include entities from child channels? if (children != null) { var channelIds = children .Select(c => c.Id) .Append(parent.Id) .ToArray(); q.CategoryId.IsIn(channelIds); } else { // Get topics for current channel q.CategoryId.Equals(parent.Id); } q.HideHidden.True(); q.HideSpam.True(); q.HideDeleted.True(); }) .OrderBy("CreatedDate", OrderBy.Desc) .ToList(); var totalEntities = 0; Doc latestEntity = null; if (topics?.Data != null) { totalEntities = topics.Total; latestEntity = topics.Data[0]; } var totalReplies = 0; DocComment latestReply = null; if (replies?.Data != null) { totalReplies = replies.Total; latestReply = replies.Data[0]; } // Update channel details with latest entity details var details = parent.GetOrCreate <CategoryDetails>(); details.TotalEntities = totalEntities; details.TotalReplies = totalReplies; if (latestEntity != null) { details.LatestEntity = new LatestPost { Id = latestEntity.Id, Alias = latestEntity.Alias, CreatedBy = latestEntity.CreatedBy, CreatedDate = latestEntity.CreatedDate }; } else { details.LatestEntity = null; } if (latestReply != null) { details.LatestReply = new LatestPost { Id = latestReply.Id, CreatedBy = latestReply.CreatedBy, CreatedDate = latestReply.CreatedDate }; } else { details.LatestReply = null; } parent.AddOrUpdate <CategoryDetails>(details); // Save the updated details await _channelManager.UpdateAsync(parent); } }
private void toolStripMenuItemInsertComment_Click(object sender, EventArgs e) { TreeNode tnParent = this.treeView.SelectedNode; DocSchema docSchema = (DocSchema)tnParent.Tag; DocComment docComment = new DocComment(); InitDefinition(docComment); docComment.Name = null; docSchema.Comments.Add(docComment); this.treeView.SelectedNode = this.LoadNode(tnParent.Nodes[9], docComment, docComment.ToString(), false); toolStripMenuItemEditProperties_Click(this, e); }
/// <summary> /// Given a documentation comment describing a Q# function or operation /// declaration, writes a Markdown file documenting that callable /// declaration to <see cref="OutputPath" />. /// </summary> /// <param name="callable">The Q# callable being documented.</param> /// <param name="docComment"> /// The API documentation comment describing <paramref name="callable"/>. /// </param> /// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns> public async Task WriteOutput(QsCallable callable, DocComment docComment) { // Make a new Markdown document for the type declaration. var kind = callable.Kind.Tag switch { QsCallableKind.Tags.Function => "function", QsCallableKind.Tags.Operation => "operation", QsCallableKind.Tags.TypeConstructor => "type constructor", _ => "<unknown>", }; var title = $@"{callable.FullName.Name} {kind}"; var header = new Dictionary <string, object> { // DocFX metadata ["uid"] = callable.FullName.ToString(), ["title"] = title, // docs.ms metadata ["ms.date"] = DateTime.Today.ToString(), ["ms.topic"] = "article", // Q# metadata ["qsharp.kind"] = kind, ["qsharp.namespace"] = callable.FullName.Namespace, ["qsharp.name"] = callable.FullName.Name, ["qsharp.summary"] = docComment.Summary, }; var document = $@" # {title} Namespace: [{callable.FullName.Namespace}](xref:{callable.FullName.Namespace}) {this.packageLink} {docComment.Summary} ```{this.LanguageMode} { callable.Kind.Tag switch { QsCallableKind.Tags.Function => "function ", QsCallableKind.Tags.Operation => "operation ", QsCallableKind.Tags.TypeConstructor => "newtype ", _ => "" } }{callable.ToSyntax()} ``` " .MaybeWithSection("Description", docComment.Description) .MaybeWithSection( "Input", string.Join("\n", callable.ArgumentTuple.InputDeclarations().Select( (item) => { (var inputName, var resolvedType) = item; var documentation = docComment.Input.TryGetValue(inputName, out var inputComment) ? inputComment : string.Empty; return($"### {inputName} : {resolvedType.ToMarkdownLink()}\n\n{documentation}\n\n"); } )) ) .WithSection($"Output : {callable.Signature.ReturnType.ToMarkdownLink()}", docComment.Output) .MaybeWithSection( "Type Parameters", string.Join("\n", callable.Signature.TypeParameters.Select( typeParam => typeParam is QsLocalSymbol.ValidName name ? $@"### '{name.Item}{"\n\n"}{( docComment.TypeParameters.TryGetValue($"'{name.Item}", out var comment) ? comment : string.Empty )}" : string.Empty )) ) .MaybeWithSection("Remarks", docComment.Remarks) .MaybeWithSection("References", docComment.References) .MaybeWithSection( "See Also", string.Join("\n", docComment.SeeAlso.Select( seeAlso => AsSeeAlsoLink(seeAlso, callable.FullName.Namespace) )) ) .WithYamlHeader(header); // Open a file to write the new doc to. await this.WriteAllTextAsync( $"{callable.FullName.Namespace}.{callable.FullName.Name}.md", document ); }
/// <summary> /// Given a documentation comment describing a Q# user-defined type /// declaration, writes a Markdown file documenting that UDT /// declaration to <see cref="OutputPath" />. /// </summary> /// <param name="type">The Q# UDT being documented.</param> /// <param name="docComment"> /// The API documentation comment describing <paramref name="type"/>. /// </param> /// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns> public async Task WriteOutput(QsCustomType type, DocComment docComment) { var namedItemDeclarations = type.TypeItems.ToDictionaryOfDeclarations(); // Make a new Markdown document for the type declaration. var title = $"{type.FullName.Name} user defined type"; var header = new Dictionary <string, object> { // DocFX metadata ["uid"] = type.FullName.ToString(), ["title"] = title, // docs.ms metadata ["ms.date"] = DateTime.Today.ToString(), ["ms.topic"] = "article", // Q# metadata ["qsharp.kind"] = "udt", ["qsharp.namespace"] = type.FullName.Namespace, ["qsharp.name"] = type.FullName.Name, ["qsharp.summary"] = docComment.Summary, }; var document = $@" # {title} Namespace: [{type.FullName.Namespace}](xref:{type.FullName.Namespace}) {this.packageLink} {docComment.Summary} ```{this.LanguageMode} {type.WithoutDocumentationAndComments().ToSyntax()} ``` " .MaybeWithSection( "Named Items", string.Join("\n", type.TypeItems.TypeDeclarations().Select( item => { (var itemName, var resolvedType) = item; var documentation = docComment.NamedItems.TryGetValue(itemName, out var comment) ? comment : string.Empty; return($"### {itemName} : {resolvedType.ToMarkdownLink()}\n\n{documentation}"); } )) ) .MaybeWithSection("Description", docComment.Description) .MaybeWithSection("Remarks", docComment.Remarks) .MaybeWithSection("References", docComment.References) .MaybeWithSection( "See Also", string.Join("\n", docComment.SeeAlso.Select( seeAlso => AsSeeAlsoLink(seeAlso, type.FullName.Namespace) )) ) .WithYamlHeader(header); // Open a file to write the new doc to. await this.WriteAllTextAsync( $"{type.FullName.Namespace}.{type.FullName.Name}.md", document ); }
/// <summary> /// Creates a documentation schema from a VEX schema /// </summary> /// <param name="schemata">The VEX schema to import</param> /// <param name="project">The documentation project where the imported schema is to be created</param> /// <returns>The imported documentation schema</returns> internal static DocSchema ImportVex(SCHEMATA schemata, DocProject docProject, bool updateDescriptions) { DocSchema docSchema = docProject.RegisterSchema(schemata.name); if (updateDescriptions && schemata.comment != null && schemata.comment.text != null) { docSchema.Documentation = schemata.comment.text.text; } docSchema.DiagramPagesHorz = schemata.settings.page.nhorizontalpages; docSchema.DiagramPagesVert = schemata.settings.page.nverticalpages; // remember current types for deletion if they no longer exist List<DocObject> existing = new List<DocObject>(); foreach (DocType doctype in docSchema.Types) { existing.Add(doctype); } foreach (DocEntity docentity in docSchema.Entities) { existing.Add(docentity); } foreach (DocFunction docfunction in docSchema.Functions) { existing.Add(docfunction); } foreach (DocGlobalRule docrule in docSchema.GlobalRules) { existing.Add(docrule); } docSchema.PageTargets.Clear(); docSchema.SchemaRefs.Clear(); docSchema.Comments.Clear(); // remember references for fixing up attributes afterwords Dictionary<object, DocDefinition> mapRefs = new Dictionary<object, DocDefinition>(); Dictionary<ATTRIBUTE_DEF, DocAttribute> mapAtts = new Dictionary<ATTRIBUTE_DEF, DocAttribute>(); //Dictionary<SELECT_DEF, DocSelectItem> mapSels = new Dictionary<SELECT_DEF, DocSelectItem>(); Dictionary<SELECT_DEF, DocLine> mapSL = new Dictionary<SELECT_DEF, DocLine>(); Dictionary<SUBTYPE_DEF, DocLine> mapSubs = new Dictionary<SUBTYPE_DEF, DocLine>(); Dictionary<PAGE_REF, DocPageTarget> mapPage = new Dictionary<PAGE_REF, DocPageTarget>(); // entities and types foreach (object obj in schemata.objects) { if (obj is ENTITIES) { ENTITIES ent = (ENTITIES)obj; // filter out orphaned entities having upper flags set if ((ent.flag & 0xFFFF0000) == 0 && (ent.interfaceto == null || ent.interfaceto.theschema == null)) { // create if doesn't exist string name = ent.name.text; string super = null; if (ent.supertypes.Count > 0 && ent.supertypes[0].the_supertype is ENTITIES) { ENTITIES superent = (ENTITIES)ent.supertypes[0].the_supertype; super = superent.name.text; } DocEntity docEntity = docSchema.RegisterEntity(name); if (existing.Contains(docEntity)) { existing.Remove(docEntity); } mapRefs.Add(obj, docEntity); // clear out existing if merging docEntity.BaseDefinition = null; foreach(DocSubtype docSub in docEntity.Subtypes) { docSub.Delete(); } docEntity.Subtypes.Clear(); foreach(DocUniqueRule docUniq in docEntity.UniqueRules) { docUniq.Delete(); } docEntity.UniqueRules.Clear(); foreach(DocLine docLine in docEntity.Tree) { docLine.Delete(); } docEntity.Tree.Clear(); if (updateDescriptions && ent.comment != null && ent.comment.text != null) { docEntity.Documentation = ent.comment.text.text; } if (ent.supertypes.Count > 0 && ent.supertypes[0].the_supertype is ENTITIES) { docEntity.BaseDefinition = ((ENTITIES)ent.supertypes[0].the_supertype).name.text; } docEntity.EntityFlags = ent.flag; if (ent.subtypes != null) { foreach (SUBTYPE_DEF sd in ent.subtypes) { // new (3.8): intermediate subtypes for diagrams DocLine docLine = new DocLine(); ImportVexLine(sd.layout, null, docLine.DiagramLine, null); docEntity.Tree.Add(docLine); OBJECT od = (OBJECT)sd.the_subtype; // tunnel through page ref if (od is PAGE_REF_TO) { od = ((PAGE_REF_TO)od).pageref; } if (od is TREE) { TREE tree = (TREE)od; foreach (OBJECT o in tree.list) { OBJECT os = o; OBJECT_LINE_LAYOUT linelayout = null; if (o is SUBTYPE_DEF) { SUBTYPE_DEF osd = (SUBTYPE_DEF)o; linelayout = osd.layout; os = ((SUBTYPE_DEF)o).the_subtype; } if (os is PAGE_REF_TO) { os = ((PAGE_REF_TO)os).pageref; } if (os is ENTITIES) { DocSubtype docSub = new DocSubtype(); docSub.DefinedType = ((ENTITIES)os).name.text; docEntity.Subtypes.Add(docSub); DocLine docSubline = new DocLine(); docLine.Tree.Add(docSubline); if (o is SUBTYPE_DEF) { mapSubs.Add((SUBTYPE_DEF)o, docSubline); } ImportVexLine(linelayout, null, docSubline.DiagramLine, null); } else { Debug.Assert(false); } } } else if (od is ENTITIES) { DocSubtype docInt = new DocSubtype(); docEntity.Subtypes.Add(docInt); docInt.DefinedType = ((ENTITIES)od).name.text; } else { Debug.Assert(false); } } } // determine EXPRESS-G page based on placement (required for generating hyperlinks) if (ent.layout != null) { ImportVexRectangle(docEntity, ent.layout.rectangle, schemata); } if (ent.attributes != null) { List<DocAttribute> existingattr = new List<DocAttribute>(); foreach (DocAttribute docAttr in docEntity.Attributes) { existingattr.Add(docAttr); } // attributes are replaced, not merged (template don't apply here) foreach (ATTRIBUTE_DEF attr in ent.attributes) { if (attr.name != null) { DocAttribute docAttr = docEntity.RegisterAttribute(attr.name.text); mapAtts.Add(attr, docAttr); if (existingattr.Contains(docAttr)) { existingattr.Remove(docAttr); } if (updateDescriptions && attr.comment != null && attr.comment.text != null) { docAttr.Documentation = attr.comment.text.text; } if (docAttr.DiagramLabel != null) { docAttr.DiagramLabel.Delete(); docAttr.DiagramLabel = null; } foreach(DocPoint docPoint in docAttr.DiagramLine) { docPoint.Delete(); } docAttr.DiagramLine.Clear(); if (attr.layout != null) { if (attr.layout.pline != null) { // intermediate lines if (attr.layout.pline.rpoint != null) { docAttr.DiagramLabel = new DocRectangle(); ImportVexLine(attr.layout, attr.name.layout, docAttr.DiagramLine, docAttr.DiagramLabel); } } } OBJECT def = attr.the_attribute; if (attr.the_attribute is PAGE_REF_TO) { PAGE_REF_TO pr = (PAGE_REF_TO)attr.the_attribute; def = pr.pageref; } if (def is DEFINED_TYPE) { DEFINED_TYPE dt = (DEFINED_TYPE)def; docAttr.DefinedType = dt.name.text; } else if (def is ENTITIES) { ENTITIES en = (ENTITIES)def; docAttr.DefinedType = en.name.text; } else if (def is ENUMERATIONS) { ENUMERATIONS en = (ENUMERATIONS)def; docAttr.DefinedType = en.name.text; } else if (def is SELECTS) { SELECTS en = (SELECTS)def; docAttr.DefinedType = en.name.text; } else if (def is PRIMITIVE_TYPE) { PRIMITIVE_TYPE en = (PRIMITIVE_TYPE)def; string length = ""; if (en.constraints > 0) { length = " (" + en.constraints.ToString() + ")"; } else if (en.constraints < 0) { int len = -en.constraints; length = " (" + len.ToString() + ") FIXED"; } docAttr.DefinedType = en.name.text + length; } else if (def is SCHEMA_REF) { SCHEMA_REF en = (SCHEMA_REF)def; docAttr.DefinedType = en.name.text; } else { Debug.Assert(false); } docAttr.AttributeFlags = attr.attributeflag; AGGREGATES vexAggregates = attr.aggregates; DocAttribute docAggregate = docAttr; while (vexAggregates != null) { // traverse nested aggregation (e.g. IfcStructuralLoadConfiguration) docAggregate.AggregationType = vexAggregates.aggrtype + 1; docAggregate.AggregationLower = vexAggregates.lower; docAggregate.AggregationUpper = vexAggregates.upper; docAggregate.AggregationFlag = vexAggregates.flag; vexAggregates = vexAggregates.next; if (vexAggregates != null) { // inner array (e.g. IfcStructuralLoadConfiguration) docAggregate.AggregationAttribute = new DocAttribute(); docAggregate = docAggregate.AggregationAttribute; } } docAttr.Derived = attr.is_derived; if (attr.user_redeclaration != null) { docAttr.Inverse = attr.user_redeclaration; } else if (attr.is_inverse is ATTRIBUTE_DEF) { ATTRIBUTE_DEF adef = (ATTRIBUTE_DEF)attr.is_inverse; docAttr.Inverse = adef.name.text; } else if (attr.is_inverse != null) { Debug.Assert(false); } } } foreach(DocAttribute docAttr in existingattr) { docEntity.Attributes.Remove(docAttr); docAttr.Delete(); } } // unique rules if (ent.uniquenes != null) { // rules are replaced, not merged (template don't apply here) //docEntity.UniqueRules = new List<DocUniqueRule>(); foreach (UNIQUE_RULE rule in ent.uniquenes) { DocUniqueRule docRule = new DocUniqueRule(); docEntity.UniqueRules.Add(docRule); docRule.Name = rule.name; docRule.Items = new List<DocUniqueRuleItem>(); foreach (ATTRIBUTE_DEF ruleitem in rule.for_attribute) { DocUniqueRuleItem item = new DocUniqueRuleItem(); item.Name = ruleitem.name.text; docRule.Items.Add(item); } } } // where rules if (ent.wheres != null) { List<DocWhereRule> existingattr = new List<DocWhereRule>(); foreach (DocWhereRule docWhere in docEntity.WhereRules) { existingattr.Add(docWhere); } foreach (WHERE_RULE where in ent.wheres) { DocWhereRule docWhere = docEntity.RegisterWhereRule(where.name); docWhere.Expression = where.rule_context; if(existingattr.Contains(docWhere)) { existingattr.Remove(docWhere); } if (updateDescriptions && where.comment != null && where.comment.text != null) { docWhere.Documentation = where.comment.text.text; } } foreach(DocWhereRule exist in existingattr) { exist.Delete(); docEntity.WhereRules.Remove(exist); } } } } else if (obj is ENUMERATIONS) { ENUMERATIONS ent = (ENUMERATIONS)obj; if (ent.interfaceto == null || ent.interfaceto.theschema == null) { if (schemata.name.Equals("IfcConstructionMgmtDomain", StringComparison.OrdinalIgnoreCase) && ent.name.text.Equals("IfcNullStyle", StringComparison.OrdinalIgnoreCase)) { // hack to workaround vex bug Debug.Assert(true); } else { DocEnumeration docEnumeration = docSchema.RegisterType<DocEnumeration>(ent.name.text); if (existing.Contains(docEnumeration)) { existing.Remove(docEnumeration); } mapRefs.Add(obj, docEnumeration); if (updateDescriptions && ent.comment != null && ent.comment.text != null) { docEnumeration.Documentation = ent.comment.text.text; } // determine EXPRESS-G page based on placement (required for generating hyperlinks) if (ent.typelayout != null && schemata.settings != null && schemata.settings.page != null) { ImportVexRectangle(docEnumeration, ent.typelayout.rectangle, schemata); } // enumeration values are replaced, not merged (template don't apply here) docEnumeration.Constants.Clear(); foreach (string s in ent.enums) { DocConstant docConstant = new DocConstant(); docEnumeration.Constants.Add(docConstant); docConstant.Name = s; } } } } else if (obj is DEFINED_TYPE) { DEFINED_TYPE ent = (DEFINED_TYPE)obj; if (ent.interfaceto == null || ent.interfaceto.theschema == null) { DocDefined docDefined = docSchema.RegisterType<DocDefined>(ent.name.text); if (existing.Contains(docDefined)) { existing.Remove(docDefined); } mapRefs.Add(obj, docDefined); if (updateDescriptions && ent.comment != null && ent.comment.text != null) { docDefined.Documentation = ent.comment.text.text; } if (ent.layout != null) { ImportVexRectangle(docDefined, ent.layout.rectangle, schemata); } if(ent.defined.object_line_layout != null) { foreach(DocPoint docPoint in docDefined.DiagramLine) { docPoint.Delete(); } docDefined.DiagramLine.Clear(); ImportVexLine(ent.defined.object_line_layout, null, docDefined.DiagramLine, null); } OBJECT os = (OBJECT)ent.defined.defined; if (os is PAGE_REF_TO) { os = ((PAGE_REF_TO)os).pageref; } if (os is PRIMITIVE_TYPE) { PRIMITIVE_TYPE pt = (PRIMITIVE_TYPE)os; docDefined.DefinedType = pt.name.text; if (pt.constraints != 0) { docDefined.Length = pt.constraints; } } else if (os is DEFINED_TYPE) { DEFINED_TYPE dt = (DEFINED_TYPE)os; docDefined.DefinedType = dt.name.text; } else if (os is ENTITIES) { ENTITIES et = (ENTITIES)os; docDefined.DefinedType = et.name.text; } else { Debug.Assert(false); } // aggregation AGGREGATES vexAggregates = ent.defined.aggregates; if (vexAggregates != null) { DocAttribute docAggregate = new DocAttribute(); docDefined.Aggregation = docAggregate; docAggregate.AggregationType = vexAggregates.aggrtype + 1; docAggregate.AggregationLower = vexAggregates.lower; docAggregate.AggregationUpper = vexAggregates.upper; docAggregate.AggregationFlag = vexAggregates.flag; } // where rules if (ent.whererules != null) { // rules are replaced, not merged (template don't apply here) foreach(DocWhereRule docWhere in docDefined.WhereRules) { docWhere.Delete(); } docDefined.WhereRules.Clear(); foreach (WHERE_RULE where in ent.whererules) { DocWhereRule docWhere = new DocWhereRule(); docDefined.WhereRules.Add(docWhere); docWhere.Name = where.name; docWhere.Expression = where.rule_context; if (where.comment != null && where.comment.text != null) { docWhere.Documentation = where.comment.text.text; } } } } } else if (obj is SELECTS) { SELECTS ent = (SELECTS)obj; if (ent.interfaceto == null || ent.interfaceto.theschema == null) { DocSelect docSelect = docSchema.RegisterType<DocSelect>(ent.name.text); if (existing.Contains(docSelect)) { existing.Remove(docSelect); } mapRefs.Add(obj, docSelect); if (updateDescriptions && ent.comment != null && ent.comment.text != null) { docSelect.Documentation = ent.comment.text.text; } // determine EXPRESS-G page based on placement (required for generating hyperlinks) if (ent.typelayout != null) { ImportVexRectangle(docSelect, ent.typelayout.rectangle, schemata); } docSelect.Selects.Clear(); docSelect.Tree.Clear(); foreach (SELECT_DEF sdef in ent.selects) { DocLine docLine = new DocLine(); docSelect.Tree.Add(docLine); ImportVexLine(sdef.layout, null, docLine.DiagramLine, null); mapSL.Add(sdef, docLine); if (sdef.def is TREE) { TREE tree = (TREE)sdef.def; foreach (OBJECT o in tree.list) { DocSelectItem dsi = new DocSelectItem(); docSelect.Selects.Add(dsi); OBJECT os = o; if (o is SELECT_DEF) { SELECT_DEF selectdef = (SELECT_DEF)o; DocLine docLineSub = new DocLine(); docLine.Tree.Add(docLineSub); ImportVexLine(selectdef.layout, null, docLineSub.DiagramLine, null); mapSL.Add(selectdef, docLineSub); os = ((SELECT_DEF)o).def; } else { Debug.Assert(false); } if (os is PAGE_REF_TO) { PAGE_REF_TO pr = (PAGE_REF_TO)os; os = pr.pageref; } if (os is DEFINITION) { dsi.Name = ((DEFINITION)os).name.text; } } } else { OBJECT os = (OBJECT)sdef.def; if (os is PAGE_REF_TO) { PAGE_REF_TO pr = (PAGE_REF_TO)os; os = pr.pageref; } DocSelectItem dsi = new DocSelectItem(); docSelect.Selects.Add(dsi); if (os is DEFINITION) { dsi.Name = ((DEFINITION)os).name.text; } } } } } else if (obj is GLOBAL_RULE) { GLOBAL_RULE func = (GLOBAL_RULE)obj; DocGlobalRule docFunction = docSchema.RegisterRule(func.name); if (existing.Contains(docFunction)) { existing.Remove(docFunction); } // clear out existing if merging docFunction.WhereRules.Clear(); if (updateDescriptions && func.comment != null && func.comment.text != null) { docFunction.Documentation = func.comment.text.text; } docFunction.Expression = func.rule_context; foreach (WHERE_RULE wr in func.where_rule) { DocWhereRule docW = new DocWhereRule(); docW.Name = wr.name; docW.Expression = wr.rule_context; if (wr.comment != null) { docW.Documentation = wr.comment.text.text; } docFunction.WhereRules.Add(docW); } if (func.for_entities.Count == 1) { docFunction.ApplicableEntity = func.for_entities[0].ToString(); } } else if (obj is USER_FUNCTION) { USER_FUNCTION func = (USER_FUNCTION)obj; DocFunction docFunction = docSchema.RegisterFunction(func.name); if (existing.Contains(docFunction)) { existing.Remove(docFunction); } if (updateDescriptions && func.comment != null && func.comment.text != null) { docFunction.Documentation = func.comment.text.text; } docFunction.Expression = func.rule_context; // NOTE: While the VEX schema can represent parameters and return values, Visual Express does not implement it! // Rather, parameter info is also included in the 'rule_context' if (func.return_value != null) { docFunction.ReturnValue = func.return_value.ToString(); } else { docFunction.ReturnValue = null; } docFunction.Parameters.Clear(); if (func.parameter_list != null) { foreach (PARAMETER par in func.parameter_list) { DocParameter docParameter = new DocParameter(); docParameter.Name = par.name; docParameter.DefinedType = par.parameter_type.ToString(); docFunction.Parameters.Add(docParameter); } } } else if (obj is PRIMITIVE_TYPE) { PRIMITIVE_TYPE prim = (PRIMITIVE_TYPE)obj; DocPrimitive docPrimitive = new DocPrimitive(); docPrimitive.Name = prim.name.text; if (prim.layout != null) { ImportVexRectangle(docPrimitive, prim.layout.rectangle, schemata); } docSchema.Primitives.Add(docPrimitive); mapRefs.Add(obj, docPrimitive); } else if (obj is COMMENT) { COMMENT comment = (COMMENT)obj; // only deal with comments that are part of EXPRESS-G layout -- ignore those referenced by definitions and old cruft left behind due to older versions of VisualE that were buggy if (comment.layout != null) { DocComment docComment = new DocComment(); docComment.Documentation = comment.text.text; ImportVexRectangle(docComment, comment.layout.rectangle, schemata); docSchema.Comments.Add(docComment); } } else if (obj is INTERFACE_SCHEMA) { INTERFACE_SCHEMA iface = (INTERFACE_SCHEMA)obj; DocSchemaRef docSchemaRef = new DocSchemaRef(); docSchema.SchemaRefs.Add(docSchemaRef); docSchemaRef.Name = iface.schema_name; foreach (object o in iface.item) { if (o is DEFINITION) { DocDefinitionRef docDefRef = new DocDefinitionRef(); docSchemaRef.Definitions.Add(docDefRef); mapRefs.Add(o, docDefRef); docDefRef.Name = ((DEFINITION)o).name.text; if (o is DEFINED_TYPE) { DEFINED_TYPE dt = (DEFINED_TYPE)o; if (dt.layout != null) { ImportVexRectangle(docDefRef, dt.layout.rectangle, schemata); } } else if (o is ENTITIES) { ENTITIES ents = (ENTITIES)o; if (ents.layout != null) // null for IfcPolyline reference in IfcGeometricModelResource { ImportVexRectangle(docDefRef, ents.layout.rectangle, schemata); } if (ents.subtypes != null) { foreach (SUBTYPE_DEF subdef in ents.subtypes) { OBJECT_LINE_LAYOUT linelayout = subdef.layout; DocLine docSub = new DocLine(); ImportVexLine(subdef.layout, null, docSub.DiagramLine, null); docDefRef.Tree.Add(docSub); if(subdef.the_subtype is TREE) { TREE tree = (TREE)subdef.the_subtype; foreach(object oo in tree.list) { if(oo is SUBTYPE_DEF) { SUBTYPE_DEF subsubdef = (SUBTYPE_DEF)oo; DocLine docSubSub = new DocLine(); docSub.Tree.Add(docSubSub); ImportVexLine(subsubdef.layout, null, docSubSub.DiagramLine, null); mapSubs.Add(subsubdef, docSubSub); } } } } } } else if (o is ENUMERATIONS) { ENUMERATIONS enums = (ENUMERATIONS)o; if (enums.typelayout != null) { ImportVexRectangle(docDefRef, enums.typelayout.rectangle, schemata); } } else if (o is SELECTS) { SELECTS sels = (SELECTS)o; if (sels.typelayout != null) { ImportVexRectangle(docDefRef, sels.typelayout.rectangle, schemata); } } else if(o is SCHEMA_REF) { SCHEMA_REF sref = (SCHEMA_REF)o; if(sref.layout != null) { ImportVexRectangle(docDefRef, sref.layout.rectangle, schemata); } } } else if (o is USER_FUNCTION) { DocDefinitionRef docDefRef = new DocDefinitionRef(); docSchemaRef.Definitions.Add(docDefRef); USER_FUNCTION uf = (USER_FUNCTION)o; docDefRef.Name = uf.name; } } } else if (obj is PAGE_REF) { PAGE_REF pageref = (PAGE_REF)obj; DocPageTarget docPageTarget = new DocPageTarget(); docSchema.PageTargets.Add(docPageTarget); docPageTarget.Name = pageref.text.text; docPageTarget.DiagramNumber = pageref.pagenr; ImportVexLine(pageref.pageline.layout, null, docPageTarget.DiagramLine, null); ImportVexRectangle(docPageTarget, pageref.layout.rectangle, schemata); foreach (PAGE_REF_TO pagerefto in pageref.pagerefto) { DocPageSource docPageSource = new DocPageSource(); docPageTarget.Sources.Add(docPageSource); docPageSource.DiagramNumber = pagerefto.pagenr; docPageSource.Name = pagerefto.text.text; ImportVexRectangle(docPageSource, pagerefto.layout.rectangle, schemata); mapRefs.Add(pagerefto, docPageSource); } mapPage.Add(pageref, docPageTarget); } } foreach (DocObject docobj in existing) { if (docobj is DocEntity) { docSchema.Entities.Remove((DocEntity)docobj); } else if (docobj is DocType) { docSchema.Types.Remove((DocType)docobj); } else if (docobj is DocFunction) { docSchema.Functions.Remove((DocFunction)docobj); } else if (docobj is DocGlobalRule) { docSchema.GlobalRules.Remove((DocGlobalRule)docobj); } docobj.Delete(); } // now fix up attributes foreach (ATTRIBUTE_DEF docAtt in mapAtts.Keys) { DocAttribute docAttr = mapAtts[docAtt]; docAttr.Definition = mapRefs[docAtt.the_attribute]; } foreach (PAGE_REF page in mapPage.Keys) { DocPageTarget docPage = mapPage[page]; docPage.Definition = mapRefs[page.pageline.pageref]; } foreach (SELECT_DEF sd in mapSL.Keys) { DocLine docLine = mapSL[sd]; if (mapRefs.ContainsKey(sd.def)) { docLine.Definition = mapRefs[sd.def]; } } foreach (SUBTYPE_DEF sd in mapSubs.Keys) { DocLine docLine = mapSubs[sd]; if (mapRefs.ContainsKey(sd.the_subtype)) { docLine.Definition = mapRefs[sd.the_subtype]; } } foreach(object o in mapRefs.Keys) { if (o is DEFINED_TYPE) { DEFINED_TYPE def = (DEFINED_TYPE)o; if (def.interfaceto == null || def.interfaceto.theschema == null) { // declared within DocDefined docDef = (DocDefined)mapRefs[o]; docDef.Definition = mapRefs[def.defined.defined]; } } } return docSchema; }
// -------------------- async Task <ICommandResultBase> ApplyLatestHistoryPoint(Doc entity, DocComment reply) { // Get current user var user = await _contextFacade.GetAuthenticatedUserAsync(); // We need to be authenticated to make changes if (user == null) { return(await ResetEditDetails(entity, reply, user)); } // Get newest / most recent history entry var histories = await _entityHistoryStore.QueryAsync() .Take(1, false) .Select <EntityHistoryQueryParams>(q => { q.EntityId.Equals(entity.Id); q.EntityReplyId.Equals(reply?.Id ?? 0); }) .OrderBy("Id", OrderBy.Desc) .ToList(); // No history point, return success if (histories == null) { return(await ResetEditDetails(entity, reply, user)); } // No history point, return success if (histories.Data == null) { return(await ResetEditDetails(entity, reply, user)); } // No history point, return success if (histories.Data.Count == 0) { return(await ResetEditDetails(entity, reply, user)); } var history = histories.Data[0]; // No history available reset edit details if (history == null) { return(await ResetEditDetails(entity, reply, user)); } // Update edit details based on latest history point var result = new CommandResultBase(); if (reply != null) { reply.ModifiedUserId = user.Id; reply.ModifiedDate = DateTimeOffset.UtcNow; reply.EditedUserId = history.CreatedUserId; reply.EditedDate = history.CreatedDate; // Update reply to history point var updateResult = await _entityReplyStore.UpdateAsync(reply); if (updateResult != null) { return(result.Success()); } } else { entity.ModifiedUserId = user.Id; entity.ModifiedDate = DateTimeOffset.UtcNow; entity.EditedUserId = history.CreatedUserId; entity.EditedDate = history.CreatedDate; // Update entity to history point var updateResult = await _entityStore.UpdateAsync(entity); if (updateResult != null) { return(result.Success()); } } return(result.Success()); }
public async Task <IActionResult> Delete(int id) { // Validate if (id <= 0) { throw new ArgumentOutOfRangeException(nameof(id)); } // Get history point var history = await _entityHistoryStore.GetByIdAsync(id); // Ensure we found the entity if (history == null) { return(NotFound()); } // Get entity var entity = await _entityStore.GetByIdAsync(history.EntityId); // Ensure we found the entity if (entity == null) { return(NotFound()); } // Get reply DocComment reply = null; if (history.EntityReplyId > 0) { reply = await _entityReplyStore.GetByIdAsync(history.EntityReplyId); // Ensure we found a reply if supplied if (reply == null) { return(NotFound()); } } // Ensure we have permission if (!await _authorizationService.AuthorizeAsync(HttpContext.User, entity.CategoryId, reply != null ? Permissions.DeleteReplyHistory : Permissions.DeleteEntityHistory)) { return(Unauthorized()); } // Delete history point var result = await _entityHistoryManager.DeleteAsync(history); // Add result if (result.Succeeded) { // Update edit details for entity or reply based on latest history point var entityResult = await ApplyLatestHistoryPoint(entity, reply); if (entityResult.Succeeded) { _alerter.Success(T["Version Deleted Successfully!"]); } else { foreach (var error in entityResult.Errors) { _alerter.Danger(T[error.Description]); } } } else { foreach (var error in result.Errors) { _alerter.Danger(T[error.Description]); } } // Redirect return(Redirect(_contextFacade.GetRouteUrl(new RouteValueDictionary() { ["area"] = "Plato.Docs", ["controller"] = "Home", ["action"] = "Reply", ["opts.id"] = entity.Id, ["opts.alias"] = entity.Alias, ["opts.replyId"] = reply?.Id ?? 0 }))); }