diff options
Diffstat (limited to 'BackEnd/Timeline/Services')
10 files changed, 341 insertions, 61 deletions
diff --git a/BackEnd/Timeline/Services/Mapper/GenericMapper.cs b/BackEnd/Timeline/Services/Mapper/GenericMapper.cs new file mode 100644 index 00000000..4dd44828 --- /dev/null +++ b/BackEnd/Timeline/Services/Mapper/GenericMapper.cs @@ -0,0 +1,37 @@ +using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Security.Claims;
+using System.Threading.Tasks;
+
+namespace Timeline.Services.Mapper
+{
+ class GenericMapper : IGenericMapper
+ {
+ private readonly IServiceProvider _serviceProvider;
+ private readonly AutoMapper.IMapper _autoMapper;
+
+ public GenericMapper(IServiceProvider serviceProvider, AutoMapper.IMapper autoMapper)
+ {
+ _serviceProvider = serviceProvider;
+ _autoMapper = autoMapper;
+ }
+
+ public TDestination AutoMapperMap<TDestination>(object source)
+ {
+ return _autoMapper.Map<TDestination>(source);
+ }
+
+ public async Task<TDestination> MapAsync<TSource, TDestination>(TSource source, IUrlHelper urlHelper, ClaimsPrincipal? user)
+ {
+ var mapper = _serviceProvider.GetService<IMapper<TSource, TDestination>>();
+
+ if (mapper is not null)
+ {
+ return await mapper.MapAsync(source, urlHelper, user);
+ }
+
+ return _autoMapper.Map<TSource, TDestination>(source);
+ }
+ }
+}
diff --git a/BackEnd/Timeline/Services/Mapper/IGenericMapper.cs b/BackEnd/Timeline/Services/Mapper/IGenericMapper.cs new file mode 100644 index 00000000..2583f036 --- /dev/null +++ b/BackEnd/Timeline/Services/Mapper/IGenericMapper.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Mvc;
+using System.Security.Claims;
+using System.Threading.Tasks;
+
+namespace Timeline.Services.Mapper
+{
+ public interface IGenericMapper
+ {
+ TDestination AutoMapperMap<TDestination>(object source);
+ Task<TDestination> MapAsync<TSource, TDestination>(TSource source, IUrlHelper urlHelper, ClaimsPrincipal? user);
+ }
+}
diff --git a/BackEnd/Timeline/Services/Mapper/IMapper.cs b/BackEnd/Timeline/Services/Mapper/IMapper.cs new file mode 100644 index 00000000..ef1b619f --- /dev/null +++ b/BackEnd/Timeline/Services/Mapper/IMapper.cs @@ -0,0 +1,11 @@ +using Microsoft.AspNetCore.Mvc;
+using System.Security.Claims;
+using System.Threading.Tasks;
+
+namespace Timeline.Services.Mapper
+{
+ public interface IMapper<TSource, TDestination>
+ {
+ Task<TDestination> MapAsync(TSource source, IUrlHelper urlHelper, ClaimsPrincipal? user);
+ }
+}
diff --git a/BackEnd/Timeline/Services/Mapper/MapperExtensions.cs b/BackEnd/Timeline/Services/Mapper/MapperExtensions.cs new file mode 100644 index 00000000..03dd1189 --- /dev/null +++ b/BackEnd/Timeline/Services/Mapper/MapperExtensions.cs @@ -0,0 +1,47 @@ +using Microsoft.AspNetCore.Mvc;
+using System.Collections.Generic;
+using System.Security.Claims;
+using System.Threading.Tasks;
+
+namespace Timeline.Services.Mapper
+{
+ public static class MapperExtensions
+ {
+ public static async Task<List<TDestination>> MapListAsync<TSource, TDestination>(this IMapper<TSource, TDestination> mapper, IEnumerable<TSource> source, IUrlHelper urlHelper, ClaimsPrincipal? user)
+ {
+ var result = new List<TDestination>();
+ foreach (var s in source)
+ {
+ result.Add(await mapper.MapAsync(s, urlHelper, user));
+ }
+ return result;
+ }
+
+ public static Task<TDestination> MapAsync<TDestination>(this IGenericMapper mapper, object source, IUrlHelper urlHelper, ClaimsPrincipal? user)
+ {
+ var method = typeof(IGenericMapper).GetMethod(nameof(IGenericMapper.MapAsync));
+ var m = method!.MakeGenericMethod(source.GetType(), typeof(TDestination))!;
+ return (Task<TDestination>)m.Invoke(mapper, new object?[] { source, urlHelper, user })!;
+ }
+
+ public static async Task<List<TDestination>> MapListAsync<TSource, TDestination>(this IGenericMapper mapper, IEnumerable<TSource> source, IUrlHelper urlHelper, ClaimsPrincipal? user)
+ {
+ var result = new List<TDestination>();
+ foreach (var s in source)
+ {
+ result.Add(await mapper.MapAsync<TSource, TDestination>(s, urlHelper, user));
+ }
+ return result;
+ }
+
+ public static async Task<List<TDestination>> MapListAsync<TDestination>(this IGenericMapper mapper, IEnumerable<object> source, IUrlHelper urlHelper, ClaimsPrincipal? user)
+ {
+ var result = new List<TDestination>();
+ foreach (var s in source)
+ {
+ result.Add(await mapper.MapAsync<TDestination>(s, urlHelper, user));
+ }
+ return result;
+ }
+ }
+}
diff --git a/BackEnd/Timeline/Services/Mapper/MapperServiceCollectionExtensions.cs b/BackEnd/Timeline/Services/Mapper/MapperServiceCollectionExtensions.cs index 262b2f20..0c2d0cfd 100644 --- a/BackEnd/Timeline/Services/Mapper/MapperServiceCollectionExtensions.cs +++ b/BackEnd/Timeline/Services/Mapper/MapperServiceCollectionExtensions.cs @@ -1,4 +1,6 @@ using Microsoft.Extensions.DependencyInjection;
+using Timeline.Entities;
+using Timeline.Models.Http;
namespace Timeline.Services.Mapper
{
@@ -6,8 +8,11 @@ namespace Timeline.Services.Mapper {
public static void AddMappers(this IServiceCollection services)
{
- services.AddScoped<UserMapper, UserMapper>();
- services.AddScoped<TimelineMapper, TimelineMapper>();
+ services.AddAutoMapper(typeof(Startup).Assembly);
+ services.AddScoped<IMapper<UserEntity, HttpUser>, UserMapper>();
+ services.AddScoped<IMapper<TimelineEntity, HttpTimeline>, TimelineMapper>();
+ services.AddScoped<IMapper<TimelinePostEntity, HttpTimelinePost>, TimelineMapper>();
+ services.AddScoped<IGenericMapper, GenericMapper>();
}
}
}
diff --git a/BackEnd/Timeline/Services/Mapper/Resource.Designer.cs b/BackEnd/Timeline/Services/Mapper/Resource.Designer.cs new file mode 100644 index 00000000..71aab793 --- /dev/null +++ b/BackEnd/Timeline/Services/Mapper/Resource.Designer.cs @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Timeline.Services.Mapper {
+ using System;
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resource {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resource() {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Timeline.Services.Mapper.Resource", typeof(Resource).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to This map is unsupported by this map provider..
+ /// </summary>
+ internal static string ExceptionUnsupportedMap {
+ get {
+ return ResourceManager.GetString("ExceptionUnsupportedMap", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/BackEnd/Timeline/Services/Mapper/Resource.resx b/BackEnd/Timeline/Services/Mapper/Resource.resx new file mode 100644 index 00000000..f075c1bb --- /dev/null +++ b/BackEnd/Timeline/Services/Mapper/Resource.resx @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" use="required" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ <xsd:attribute ref="xml:space" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <data name="ExceptionUnsupportedMap" xml:space="preserve">
+ <value>This map is unsupported by this map provider.</value>
+ </data>
+</root>
\ No newline at end of file diff --git a/BackEnd/Timeline/Services/Mapper/TimelineMapper.cs b/BackEnd/Timeline/Services/Mapper/TimelineMapper.cs index c8279b42..5ee90a8f 100644 --- a/BackEnd/Timeline/Services/Mapper/TimelineMapper.cs +++ b/BackEnd/Timeline/Services/Mapper/TimelineMapper.cs @@ -2,25 +2,29 @@ using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
+using System.Security.Claims;
using System.Threading.Tasks;
+using Timeline.Auth;
using Timeline.Controllers;
using Timeline.Entities;
using Timeline.Models.Http;
using Timeline.Services.Api;
using Timeline.Services.Timeline;
+using Timeline.Services.User;
namespace Timeline.Services.Mapper
{
- public class TimelineMapper
+ public class TimelineMapper : IMapper<TimelineEntity, HttpTimeline>,
+ IMapper<TimelinePostEntity, HttpTimelinePost>
{
private readonly DatabaseContext _database;
- private readonly UserMapper _userMapper;
+ private readonly IMapper<UserEntity, HttpUser> _userMapper;
private readonly IHighlightTimelineService _highlightTimelineService;
private readonly IBookmarkTimelineService _bookmarkTimelineService;
private readonly ITimelineService _timelineService;
private readonly ITimelinePostService _timelinePostService;
- public TimelineMapper(DatabaseContext database, UserMapper userMapper, IHighlightTimelineService highlightTimelineService, IBookmarkTimelineService bookmarkTimelineService, ITimelineService timelineService, ITimelinePostService timelinePostService)
+ public TimelineMapper(DatabaseContext database, IMapper<UserEntity, HttpUser> userMapper, IHighlightTimelineService highlightTimelineService, IBookmarkTimelineService bookmarkTimelineService, ITimelineService timelineService, ITimelinePostService timelinePostService)
{
_database = database;
_userMapper = userMapper;
@@ -30,20 +34,27 @@ namespace Timeline.Services.Mapper _timelinePostService = timelinePostService;
}
- public async Task<HttpTimeline> MapToHttp(TimelineEntity entity, IUrlHelper urlHelper, long? userId, bool isAdministrator)
+ private string CalculateTimelineName(TimelineEntity entity)
{
+ return entity.Name is null ? "@" + entity.Owner.Username : entity.Name;
+ }
+
+ public async Task<HttpTimeline> MapAsync(TimelineEntity entity, IUrlHelper urlHelper, ClaimsPrincipal? user)
+ {
+ var userId = user.GetUserId();
+
await _database.Entry(entity).Reference(e => e.Owner).LoadAsync();
await _database.Entry(entity).Collection(e => e.Members).Query().Include(m => m.User).LoadAsync();
- var timelineName = entity.Name is null ? "@" + entity.Owner.Username : entity.Name;
+ var timelineName = CalculateTimelineName(entity);
bool manageable;
- if (userId is null)
+ if (user is null || userId is null)
{
manageable = false;
}
- else if (isAdministrator)
+ else if (user.HasPermission(UserPermission.AllTimelineManagement))
{
manageable = true;
}
@@ -53,7 +64,7 @@ namespace Timeline.Services.Mapper }
bool postable;
- if (userId is null)
+ if (user is null || userId is null)
{
postable = false;
}
@@ -68,9 +79,9 @@ namespace Timeline.Services.Mapper name: timelineName,
nameLastModifed: entity.NameLastModified,
description: entity.Description ?? "",
- owner: await _userMapper.MapToHttp(entity.Owner, urlHelper),
+ owner: await _userMapper.MapAsync(entity.Owner, urlHelper, user),
visibility: entity.Visibility,
- members: await _userMapper.MapToHttp(entity.Members.Select(m => m.User).ToList(), urlHelper),
+ members: await _userMapper.MapListAsync(entity.Members.Select(m => m.User).ToList(), urlHelper, user),
color: entity.Color,
createTime: entity.CreateTime,
lastModified: entity.LastModified,
@@ -85,39 +96,31 @@ namespace Timeline.Services.Mapper );
}
- public async Task<List<HttpTimeline>> MapToHttp(List<TimelineEntity> entities, IUrlHelper urlHelper, long? userId, bool isAdministrator)
- {
- var result = new List<HttpTimeline>();
- foreach (var entity in entities)
- {
- result.Add(await MapToHttp(entity, urlHelper, userId, isAdministrator));
- }
- return result;
- }
-
- public async Task<HttpTimelinePost> MapToHttp(TimelinePostEntity entity, string timelineName, IUrlHelper urlHelper, long? userId, bool isAdministrator)
+ public async Task<HttpTimelinePost> MapAsync(TimelinePostEntity entity, IUrlHelper urlHelper, ClaimsPrincipal? user)
{
- _ = timelineName;
+ var userId = user.GetUserId();
+ await _database.Entry(entity).Reference(e => e.Timeline).LoadAsync();
await _database.Entry(entity).Collection(p => p.DataList).LoadAsync();
await _database.Entry(entity).Reference(e => e.Author).LoadAsync();
+ await _database.Entry(entity.Timeline).Reference(e => e.Owner).LoadAsync();
List<HttpTimelinePostDataDigest> dataDigestList = entity.DataList.OrderBy(d => d.Index).Select(d => new HttpTimelinePostDataDigest(d.Kind, $"\"{d.DataTag}\"", d.LastUpdated)).ToList();
HttpUser? author = null;
if (entity.Author is not null)
{
- author = await _userMapper.MapToHttp(entity.Author, urlHelper);
+ author = await _userMapper.MapAsync(entity.Author, urlHelper, user);
}
bool editable;
- if (userId is null)
+ if (user is null || userId is null)
{
editable = false;
}
- else if (isAdministrator)
+ else if (user.HasPermission(UserPermission.AllTimelineManagement))
{
editable = true;
}
@@ -126,7 +129,6 @@ namespace Timeline.Services.Mapper editable = await _timelinePostService.HasPostModifyPermissionAsync(entity.TimelineId, entity.LocalId, userId.Value);
}
-
return new HttpTimelinePost(
id: entity.LocalId,
dataList: dataDigestList,
@@ -135,24 +137,9 @@ namespace Timeline.Services.Mapper color: entity.Color,
deleted: entity.Deleted,
lastUpdated: entity.LastUpdated,
- timelineName: timelineName,
+ timelineName: CalculateTimelineName(entity.Timeline),
editable: editable
);
}
-
- public async Task<List<HttpTimelinePost>> MapToHttp(List<TimelinePostEntity> entities, string timelineName, IUrlHelper urlHelper, long? userId, bool isAdministrator)
- {
- var result = new List<HttpTimelinePost>();
- foreach (var entity in entities)
- {
- result.Add(await MapToHttp(entity, timelineName, urlHelper, userId, isAdministrator));
- }
- return result;
- }
-
- internal Task MapToHttp(TimelinePostEntity post, string timeline, IUrlHelper url)
- {
- throw new System.NotImplementedException();
- }
}
}
diff --git a/BackEnd/Timeline/Services/Mapper/UserMapper.cs b/BackEnd/Timeline/Services/Mapper/UserMapper.cs index 42f88d8a..8855eef2 100644 --- a/BackEnd/Timeline/Services/Mapper/UserMapper.cs +++ b/BackEnd/Timeline/Services/Mapper/UserMapper.cs @@ -1,5 +1,5 @@ using Microsoft.AspNetCore.Mvc;
-using System.Collections.Generic;
+using System.Security.Claims;
using System.Threading.Tasks;
using Timeline.Controllers;
using Timeline.Entities;
@@ -8,7 +8,7 @@ using Timeline.Services.User; namespace Timeline.Services.Mapper
{
- public class UserMapper
+ public class UserMapper : IMapper<UserEntity, HttpUser>
{
private readonly DatabaseContext _database;
private readonly IUserPermissionService _userPermissionService;
@@ -19,7 +19,7 @@ namespace Timeline.Services.Mapper _userPermissionService = userPermissionService;
}
- public async Task<HttpUser> MapToHttp(UserEntity entity, IUrlHelper urlHelper)
+ public async Task<HttpUser> MapAsync(UserEntity entity, IUrlHelper urlHelper, ClaimsPrincipal? user)
{
return new HttpUser(
uniqueId: entity.UniqueId,
@@ -33,15 +33,5 @@ namespace Timeline.Services.Mapper )
);
}
-
- public async Task<List<HttpUser>> MapToHttp(List<UserEntity> entities, IUrlHelper urlHelper)
- {
- var result = new List<HttpUser>();
- foreach (var entity in entities)
- {
- result.Add(await MapToHttp(entity, urlHelper));
- }
- return result;
- }
}
}
diff --git a/BackEnd/Timeline/Services/Timeline/TimelineServicesServiceCollectionExtensions.cs b/BackEnd/Timeline/Services/Timeline/TimelineServicesServiceCollectionExtensions.cs index 556800df..97b313cd 100644 --- a/BackEnd/Timeline/Services/Timeline/TimelineServicesServiceCollectionExtensions.cs +++ b/BackEnd/Timeline/Services/Timeline/TimelineServicesServiceCollectionExtensions.cs @@ -1,9 +1,5 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
namespace Timeline.Services.Timeline
{
|