diff --git a/src/redmine-net-api/Extensions/CollectionExtensions.cs b/src/redmine-net-api/Extensions/CollectionExtensions.cs
index 5a14bfe3..60703635 100755
--- a/src/redmine-net-api/Extensions/CollectionExtensions.cs
+++ b/src/redmine-net-api/Extensions/CollectionExtensions.cs
@@ -17,6 +17,7 @@ limitations under the License.
using System;
using System.Collections.Generic;
using System.Text;
+using Redmine.Net.Api.Types;
namespace Redmine.Net.Api.Extensions
{
@@ -30,8 +31,9 @@ public static class CollectionExtensions
///
///
/// The list to clone.
+ ///
///
- public static IList Clone(this IList listToClone) where T : ICloneable
+ public static IList Clone(this IList listToClone, bool resetId) where T : ICloneable
{
if (listToClone == null)
{
@@ -43,7 +45,7 @@ public static IList Clone(this IList listToClone) where T : ICloneable
for (var index = 0; index < listToClone.Count; index++)
{
var item = listToClone[index];
- clonedList.Add((T) item.Clone());
+ clonedList.Add(item.Clone(resetId));
}
return clonedList;
diff --git a/src/redmine-net-api/ICloneableOfT.cs b/src/redmine-net-api/ICloneableOfT.cs
new file mode 100644
index 00000000..dd58fde2
--- /dev/null
+++ b/src/redmine-net-api/ICloneableOfT.cs
@@ -0,0 +1,14 @@
+namespace Redmine.Net.Api;
+
+///
+///
+///
+///
+public interface ICloneable
+{
+ ///
+ ///
+ ///
+ ///
+ internal T Clone(bool resetId);
+}
\ No newline at end of file
diff --git a/src/redmine-net-api/Types/Attachment.cs b/src/redmine-net-api/Types/Attachment.cs
index f831d647..bc394f77 100644
--- a/src/redmine-net-api/Types/Attachment.cs
+++ b/src/redmine-net-api/Types/Attachment.cs
@@ -33,6 +33,7 @@ namespace Redmine.Net.Api.Types
[XmlRoot(RedmineKeys.ATTACHMENT)]
public sealed class Attachment :
Identifiable
+ , ICloneable
{
#region Properties
///
@@ -266,5 +267,39 @@ public override int GetHashCode()
Author={Author},
CreatedOn={CreatedOn?.ToString("u", CultureInfo.InvariantCulture)}]";
+ ///
+ ///
+ ///
+ ///
+ public new Attachment Clone(bool resetId)
+ {
+ if (resetId)
+ {
+ return new Attachment
+ {
+ FileName = FileName,
+ FileSize = FileSize,
+ ContentType = ContentType,
+ Description = Description,
+ ContentUrl = ContentUrl,
+ ThumbnailUrl = ThumbnailUrl,
+ Author = Author?.Clone(false),
+ CreatedOn = CreatedOn
+ };
+ }
+
+ return new Attachment
+ {
+ Id = Id,
+ FileName = FileName,
+ FileSize = FileSize,
+ ContentType = ContentType,
+ Description = Description,
+ ContentUrl = ContentUrl,
+ ThumbnailUrl = ThumbnailUrl,
+ Author = Author?.Clone(true),
+ CreatedOn = CreatedOn
+ };
+ }
}
}
\ No newline at end of file
diff --git a/src/redmine-net-api/Types/ChangeSet.cs b/src/redmine-net-api/Types/ChangeSet.cs
index bf07bc83..dae77667 100644
--- a/src/redmine-net-api/Types/ChangeSet.cs
+++ b/src/redmine-net-api/Types/ChangeSet.cs
@@ -33,6 +33,7 @@ namespace Redmine.Net.Api.Types
[DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")]
[XmlRoot(RedmineKeys.CHANGE_SET)]
public sealed class ChangeSet : IXmlSerializable, IJsonSerializable, IEquatable
+ ,ICloneable
{
#region Properties
///
@@ -157,6 +158,23 @@ public bool Equals(ChangeSet other)
&& CommittedOn == other.CommittedOn;
}
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public ChangeSet Clone(bool resetId)
+ {
+ return new ChangeSet()
+ {
+ User = User,
+ Comments = Comments,
+ Revision = Revision,
+ CommittedOn = CommittedOn,
+ };
+ }
+
///
///
///
diff --git a/src/redmine-net-api/Types/CustomFieldValue.cs b/src/redmine-net-api/Types/CustomFieldValue.cs
index 5cc91ae5..592bb4f4 100644
--- a/src/redmine-net-api/Types/CustomFieldValue.cs
+++ b/src/redmine-net-api/Types/CustomFieldValue.cs
@@ -34,6 +34,7 @@ public class CustomFieldValue :
IXmlSerializable
,IJsonSerializable
,IEquatable
+ ,ICloneable
{
///
///
@@ -205,10 +206,9 @@ public override int GetHashCode()
///
///
///
- public object Clone()
+ public CustomFieldValue Clone(bool resetId)
{
- var customFieldValue = new CustomFieldValue {Info = Info};
- return customFieldValue;
+ return new CustomFieldValue { Info = Info };
}
#endregion
diff --git a/src/redmine-net-api/Types/Detail.cs b/src/redmine-net-api/Types/Detail.cs
index 35e3fcc4..a17a0d9a 100644
--- a/src/redmine-net-api/Types/Detail.cs
+++ b/src/redmine-net-api/Types/Detail.cs
@@ -34,6 +34,7 @@ public sealed class Detail :
IXmlSerializable
,IJsonSerializable
,IEquatable
+ ,ICloneable
{
///
///
@@ -182,6 +183,16 @@ public bool Equals(Detail other)
&& string.Equals(NewValue, other.NewValue, StringComparison.OrdinalIgnoreCase);
}
+ ///
+ ///
+ ///
+ ///
+ ///
+ public Detail Clone(bool resetId)
+ {
+ return new Detail(Name, Property, OldValue, NewValue);
+ }
+
///
///
///
diff --git a/src/redmine-net-api/Types/Identifiable.cs b/src/redmine-net-api/Types/Identifiable.cs
index 24124e0c..e5123673 100644
--- a/src/redmine-net-api/Types/Identifiable.cs
+++ b/src/redmine-net-api/Types/Identifiable.cs
@@ -33,6 +33,7 @@ namespace Redmine.Net.Api.Types
///
[DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")]
public abstract class Identifiable : IXmlSerializable, IJsonSerializable, IEquatable
+ , ICloneable>
where T : Identifiable
{
#region Properties
@@ -158,5 +159,13 @@ public override int GetHashCode()
///
private string DebuggerDisplay => $"Id={Id.ToString(CultureInfo.InvariantCulture)}";
+ ///
+ ///
+ ///
+ ///
+ public virtual Identifiable Clone(bool resetId)
+ {
+ throw new NotImplementedException();
+ }
}
}
\ No newline at end of file
diff --git a/src/redmine-net-api/Types/IdentifiableName.cs b/src/redmine-net-api/Types/IdentifiableName.cs
index d9deafde..b4717d4e 100644
--- a/src/redmine-net-api/Types/IdentifiableName.cs
+++ b/src/redmine-net-api/Types/IdentifiableName.cs
@@ -29,6 +29,7 @@ namespace Redmine.Net.Api.Types
///
[DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")]
public class IdentifiableName : Identifiable
+ , ICloneable
{
///
///
@@ -224,5 +225,18 @@ public override int GetHashCode()
///
///
private string DebuggerDisplay => $"[{nameof(IdentifiableName)}: {base.ToString()}, Name={Name}]";
+
+ ///
+ ///
+ ///
+ ///
+ public new IdentifiableName Clone(bool resetId)
+ {
+ return new IdentifiableName
+ {
+ Id = Id,
+ Name = Name
+ };
+ }
}
}
\ No newline at end of file
diff --git a/src/redmine-net-api/Types/Issue.cs b/src/redmine-net-api/Types/Issue.cs
index 8559b3ce..9e97f373 100644
--- a/src/redmine-net-api/Types/Issue.cs
+++ b/src/redmine-net-api/Types/Issue.cs
@@ -40,6 +40,7 @@ namespace Redmine.Net.Api.Types
[XmlRoot(RedmineKeys.ISSUE)]
public sealed class Issue :
Identifiable
+ ,ICloneable
{
#region Properties
///
@@ -588,36 +589,51 @@ public override int GetHashCode()
}
#endregion
- #region Implementation of IClonable
+ #region Implementation of IClonable
///
///
///
///
- public object Clone()
+ public new Issue Clone(bool resetId)
{
var issue = new Issue
{
- AssignedTo = AssignedTo,
- Author = Author,
- Category = Category,
- CustomFields = CustomFields,
+ Project = Project?.Clone(false),
+ Tracker = Tracker?.Clone(false),
+ Status = Status?.Clone(false),
+ Priority = Priority?.Clone(false),
+ Author = Author?.Clone(false),
+ Category = Category?.Clone(false),
+ Subject = Subject,
Description = Description,
- DoneRatio = DoneRatio,
+ StartDate = StartDate,
DueDate = DueDate,
- SpentHours = SpentHours,
+ DoneRatio = DoneRatio,
+ IsPrivate = IsPrivate,
EstimatedHours = EstimatedHours,
- Priority = Priority,
- StartDate = StartDate,
- Status = Status,
- Subject = Subject,
- Tracker = Tracker,
- Project = Project,
- FixedVersion = FixedVersion,
+ TotalEstimatedHours = TotalEstimatedHours,
+ SpentHours = SpentHours,
+ TotalSpentHours = TotalSpentHours,
+ AssignedTo = AssignedTo?.Clone(false),
+ FixedVersion = FixedVersion?.Clone(false),
Notes = Notes,
- Watchers = Watchers
+ PrivateNotes = PrivateNotes,
+ CreatedOn = CreatedOn,
+ UpdatedOn = UpdatedOn,
+ ClosedOn = ClosedOn,
+ ParentIssue = ParentIssue?.Clone(false),
+ CustomFields = CustomFields?.Clone(false),
+ Journals = Journals?.Clone(false),
+ Attachments = Attachments?.Clone(false),
+ Relations = Relations?.Clone(false),
+ Children = Children?.Clone(false),
+ Watchers = Watchers?.Clone(false),
+ Uploads = Uploads?.Clone(false),
};
+
return issue;
}
+
#endregion
///
@@ -659,6 +675,5 @@ public IdentifiableName AsParent()
Children={Children.Dump()},
Uploads={Uploads.Dump()},
Watchers={Watchers.Dump()}]";
-
}
}
\ No newline at end of file
diff --git a/src/redmine-net-api/Types/IssueChild.cs b/src/redmine-net-api/Types/IssueChild.cs
index 317aa80f..f92e3fd4 100644
--- a/src/redmine-net-api/Types/IssueChild.cs
+++ b/src/redmine-net-api/Types/IssueChild.cs
@@ -31,6 +31,7 @@ namespace Redmine.Net.Api.Types
[DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")]
[XmlRoot(RedmineKeys.ISSUE)]
public sealed class IssueChild : Identifiable
+ ,ICloneable
{
#region Properties
///
@@ -173,12 +174,12 @@ public override int GetHashCode()
///
///
///
- public new IssueChild Clone()
+ public new IssueChild Clone(bool resetId)
{
return new IssueChild
{
Id = Id,
- Tracker = Tracker,
+ Tracker = Tracker?.Clone(false),
Subject = Subject
};
}
diff --git a/src/redmine-net-api/Types/IssueCustomField.cs b/src/redmine-net-api/Types/IssueCustomField.cs
index 5c570862..31d012cc 100644
--- a/src/redmine-net-api/Types/IssueCustomField.cs
+++ b/src/redmine-net-api/Types/IssueCustomField.cs
@@ -34,6 +34,7 @@ namespace Redmine.Net.Api.Types
public sealed class IssueCustomField :
IdentifiableName
,IEquatable
+ ,ICloneable, IValue
{
#region Properties
///
@@ -270,16 +271,37 @@ public override int GetHashCode()
}
#endregion
- #region Implementation of IClonable
+ #region Implementation of IClonable
///
///
///
///
- public object Clone()
+ public new IssueCustomField Clone(bool resetId)
{
- var issueCustomField = new IssueCustomField { Multiple = Multiple, Values = Values };
- return issueCustomField;
+ IssueCustomField clone;
+ if (resetId)
+ {
+ clone = new IssueCustomField();
+ }
+ else
+ {
+ clone = new IssueCustomField
+ {
+ Id = Id,
+ };
+ }
+
+ clone.Name = Name;
+ clone.Multiple = Multiple;
+
+ if (Values != null)
+ {
+ clone.Values = new List(Values);
+ }
+
+ return clone;
}
+
#endregion
#region Implementation of IValue
diff --git a/src/redmine-net-api/Types/IssueRelation.cs b/src/redmine-net-api/Types/IssueRelation.cs
index 84c9c501..16571f7e 100644
--- a/src/redmine-net-api/Types/IssueRelation.cs
+++ b/src/redmine-net-api/Types/IssueRelation.cs
@@ -34,6 +34,7 @@ namespace Redmine.Net.Api.Types
[XmlRoot(RedmineKeys.RELATION)]
public sealed class IssueRelation :
Identifiable
+ ,ICloneable
{
#region Properties
///
@@ -284,5 +285,30 @@ public override int GetHashCode()
Type={Type:G},
Delay={Delay?.ToString(CultureInfo.InvariantCulture)}]";
+ ///
+ ///
+ ///
+ ///
+ public new IssueRelation Clone(bool resetId)
+ {
+ if (resetId)
+ {
+ return new IssueRelation
+ {
+ IssueId = IssueId,
+ IssueToId = IssueToId,
+ Type = Type,
+ Delay = Delay
+ };
+ }
+ return new IssueRelation
+ {
+ Id = Id,
+ IssueId = IssueId,
+ IssueToId = IssueToId,
+ Type = Type,
+ Delay = Delay
+ };
+ }
}
}
\ No newline at end of file
diff --git a/src/redmine-net-api/Types/Journal.cs b/src/redmine-net-api/Types/Journal.cs
index 6f776b24..325eedbd 100644
--- a/src/redmine-net-api/Types/Journal.cs
+++ b/src/redmine-net-api/Types/Journal.cs
@@ -33,6 +33,7 @@ namespace Redmine.Net.Api.Types
[XmlRoot(RedmineKeys.JOURNAL)]
public sealed class Journal :
Identifiable
+ ,ICloneable
{
#region Properties
///
@@ -253,5 +254,32 @@ public override int GetHashCode()
///
private string DebuggerDisplay => $"[{nameof(Journal)}: {ToString()}, User={User}, Notes={Notes}, CreatedOn={CreatedOn?.ToString("u", CultureInfo.InvariantCulture)}, Details={Details.Dump()}]";
+ ///
+ ///
+ ///
+ ///
+ public new Journal Clone(bool resetId)
+ {
+ if (resetId)
+ {
+ return new Journal
+ {
+ User = User?.Clone(false),
+ Notes = Notes,
+ CreatedOn = CreatedOn,
+ PrivateNotes = PrivateNotes,
+ Details = Details?.Clone(false)
+ };
+ }
+ return new Journal
+ {
+ Id = Id,
+ User = User?.Clone(false),
+ Notes = Notes,
+ CreatedOn = CreatedOn,
+ PrivateNotes = PrivateNotes,
+ Details = Details?.Clone(false)
+ };
+ }
}
}
\ No newline at end of file
diff --git a/src/redmine-net-api/Types/TimeEntry.cs b/src/redmine-net-api/Types/TimeEntry.cs
index a6691bdb..afb8d110 100644
--- a/src/redmine-net-api/Types/TimeEntry.cs
+++ b/src/redmine-net-api/Types/TimeEntry.cs
@@ -34,6 +34,7 @@ namespace Redmine.Net.Api.Types
[DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")]
[XmlRoot(RedmineKeys.TIME_ENTRY)]
public sealed class TimeEntry : Identifiable
+ , ICloneable
{
#region Properties
private string comments;
@@ -303,7 +304,7 @@ public override int GetHashCode()
///
///
///
- public object Clone()
+ public new TimeEntry Clone(bool resetId)
{
var timeEntry = new TimeEntry
{
diff --git a/src/redmine-net-api/Types/Upload.cs b/src/redmine-net-api/Types/Upload.cs
index 00beb32f..ca2ac4ee 100644
--- a/src/redmine-net-api/Types/Upload.cs
+++ b/src/redmine-net-api/Types/Upload.cs
@@ -32,6 +32,7 @@ namespace Redmine.Net.Api.Types
[DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")]
[XmlRoot(RedmineKeys.UPLOAD)]
public sealed class Upload : IXmlSerializable, IJsonSerializable, IEquatable
+ , ICloneable
{
#region Properties
///
@@ -234,5 +235,19 @@ public override int GetHashCode()
///
private string DebuggerDisplay => $"[Upload: Token={Token}, FileName={FileName}, ContentType={ContentType}, Description={Description}]";
+ ///
+ ///
+ ///
+ ///
+ public Upload Clone(bool resetId)
+ {
+ return new Upload
+ {
+ Token = Token,
+ FileName = FileName,
+ ContentType = ContentType,
+ Description = Description
+ };
+ }
}
}
\ No newline at end of file
diff --git a/src/redmine-net-api/Types/Watcher.cs b/src/redmine-net-api/Types/Watcher.cs
index c3949e37..d413cab1 100644
--- a/src/redmine-net-api/Types/Watcher.cs
+++ b/src/redmine-net-api/Types/Watcher.cs
@@ -27,6 +27,7 @@ namespace Redmine.Net.Api.Types
[DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")]
[XmlRoot(RedmineKeys.USER)]
public sealed class Watcher : Identifiable
+ ,ICloneable
,IValue
{
#region Implementation of IValue
@@ -37,16 +38,23 @@ public sealed class Watcher : Identifiable
#endregion
- #region Implementation of ICloneable
+ #region Implementation of ICloneable
///
///
///
///
- public object Clone()
+ public new Watcher Clone(bool resetId)
{
- var watcher = new Watcher { Id = Id };
- return watcher;
+ if (resetId)
+ {
+ return new Watcher();
+ }
+ return new Watcher
+ {
+ Id = Id
+ };
}
+
#endregion
///
@@ -54,6 +62,5 @@ public object Clone()
///
///
private string DebuggerDisplay => $"[{nameof(Watcher)}: {ToString()}]";
-
}
}
\ No newline at end of file