Revize a35cb648
Přidáno uživatelem Vojtěch Bartička před téměř 3 roky(ů)
Backend/Backend/Authentication/AuthorizationAttribute.cs | ||
---|---|---|
6 | 6 |
|
7 | 7 |
namespace RestAPI.Authentication; |
8 | 8 |
|
9 |
/// <summary> |
|
10 |
/// Authorization attribute for endpoints and controllers |
|
11 |
/// By default minimum role is ANNOTATOR |
|
12 |
/// Access is granted to any role with same or higher privilege than the specified one (or default, if none is specified) |
|
13 |
/// </summary> |
|
9 | 14 |
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] |
10 | 15 |
public class AuthorizeAttribute : Attribute, IAuthorizationFilter |
11 | 16 |
{ |
Backend/Backend/Controllers/AnnotationController.cs | ||
---|---|---|
10 | 10 |
using Models.Tags; |
11 | 11 |
using Core.Services.TagService; |
12 | 12 |
|
13 |
|
|
13 |
/// <summary> |
|
14 |
/// /annotation* endpoint controller |
|
15 |
/// </summary> |
|
14 | 16 |
namespace RestAPI.Controllers |
15 | 17 |
{ |
16 | 18 |
public class AnnotationController : CommonControllerBase |
Backend/Backend/Controllers/AuthController.cs | ||
---|---|---|
10 | 10 |
|
11 | 11 |
namespace RestAPI.Controllers; |
12 | 12 |
|
13 |
/// <summary> |
|
14 |
/// Authentication controller |
|
15 |
/// </summary> |
|
13 | 16 |
public class AuthController : CommonControllerBase |
14 | 17 |
{ |
15 | 18 |
private readonly IAuthService authService; |
... | ... | |
48 | 51 |
} |
49 | 52 |
} |
50 | 53 |
|
54 |
/// <summary> |
|
55 |
/// Test only |
|
56 |
/// </summary> |
|
57 |
/// <param name="clientInfo"></param> |
|
58 |
/// <returns></returns> |
|
51 | 59 |
[HttpGet("/auth/test")] |
52 | 60 |
[ProducesResponseType((int) HttpStatusCode.OK, Type = typeof(ClientInfo))] |
53 | 61 |
[ProducesResponseType((int) HttpStatusCode.Forbidden)] |
... | ... | |
56 | 64 |
return clientInfo; |
57 | 65 |
} |
58 | 66 |
|
59 |
|
|
67 |
/// <summary> |
|
68 |
/// Test only |
|
69 |
/// </summary> |
|
70 |
/// <param name="clientInfo"></param> |
|
71 |
/// <returns></returns> |
|
60 | 72 |
[AllowAnonymous] |
61 | 73 |
[HttpGet("/auth/test/aa")] |
62 | 74 |
[ProducesResponseType((int) HttpStatusCode.OK, Type = typeof(ClientInfo))] |
Backend/Backend/Controllers/Common/CommonControllerBase.cs | ||
---|---|---|
4 | 4 |
|
5 | 5 |
namespace RestAPI.Controllers.Common; |
6 | 6 |
|
7 |
/// <summary> |
|
8 |
/// Base controller with universal headers |
|
9 |
/// Note that by default endpoints are [Authorize], so if an endpoint should not be logged-user-only, add [AllowAnonymous] |
|
10 |
/// </summary> |
|
7 | 11 |
[ApiController] |
8 | 12 |
[Authorize] |
9 | 13 |
[ProducesResponseType((int)HttpStatusCode.InternalServerError)] |
Backend/Backend/Controllers/DocumentController.cs | ||
---|---|---|
15 | 15 |
namespace RestAPI.Controllers; |
16 | 16 |
|
17 | 17 |
|
18 |
|
|
18 |
/// <summary> |
|
19 |
/// /document* endpoint controller |
|
20 |
/// </summary> |
|
19 | 21 |
public class DocumentController : Common.CommonControllerBase |
20 | 22 |
{ |
21 | 23 |
private readonly IDocumentService documentService; |
Backend/Backend/Controllers/TagController.cs | ||
---|---|---|
13 | 13 |
namespace RestAPI.Controllers; |
14 | 14 |
|
15 | 15 |
|
16 |
|
|
16 |
/// <summary> |
|
17 |
/// /tag* endpoint controller |
|
18 |
/// </summary> |
|
17 | 19 |
public class TagController : Common.CommonControllerBase |
18 | 20 |
{ |
19 | 21 |
private readonly ITagService tagService; |
20 | 22 |
private readonly ILogger logger; |
21 | 23 |
|
22 |
|
|
23 | 24 |
public TagController(ITagService tagService, ILogger logger) |
24 | 25 |
{ |
25 | 26 |
this.tagService = tagService; |
Backend/Backend/Controllers/UserController.cs | ||
---|---|---|
11 | 11 |
|
12 | 12 |
namespace RestAPI.Controllers |
13 | 13 |
{ |
14 |
/// <summary> |
|
15 |
/// /user* endpoint controller |
|
16 |
/// </summary> |
|
14 | 17 |
public class UserController : CommonControllerBase |
15 | 18 |
{ |
16 | 19 |
private readonly Serilog.ILogger logger; |
Backend/Backend/Exceptions/BadRequestException.cs | ||
---|---|---|
6 | 6 |
|
7 | 7 |
namespace RestAPI.Exceptions |
8 | 8 |
{ |
9 |
/// <summary> |
|
10 |
/// Exception raised when there is a problem with client's request |
|
11 |
/// Catched by error handling middleware |
|
12 |
/// </summary> |
|
9 | 13 |
public class BadRequestException : Exception |
10 | 14 |
{ |
11 | 15 |
public BadRequestException() { } |
Backend/Backend/Exceptions/InternalErrorException.cs | ||
---|---|---|
6 | 6 |
|
7 | 7 |
namespace RestAPI.Exceptions |
8 | 8 |
{ |
9 |
/// <summary> |
|
10 |
/// Exception raised when there is an internal server error |
|
11 |
/// Catched by error handling middleware |
|
12 |
/// </summary> |
|
9 | 13 |
public class InternalErrorException : Exception |
10 | 14 |
{ |
11 | 15 |
public InternalErrorException() { } |
Backend/Backend/Middleware/ErrorMiddleware.cs | ||
---|---|---|
4 | 4 |
|
5 | 5 |
namespace RestAPI.Middleware |
6 | 6 |
{ |
7 |
/// <summary> |
|
8 |
/// Middleware for global error handling |
|
9 |
/// </summary> |
|
7 | 10 |
public class ErrorMiddleware |
8 | 11 |
{ |
9 | 12 |
private readonly RequestDelegate _next; |
Backend/Backend/Program.cs | ||
---|---|---|
76 | 76 |
app.UseSwaggerUI(); |
77 | 77 |
} |
78 | 78 |
|
79 |
//app.UseHttpsRedirection(); |
|
80 |
|
|
81 | 79 |
// CORS |
82 | 80 |
app.UseCors(builder => builder |
83 | 81 |
.AllowAnyHeader() |
Backend/Backend/Utils/ClientInfo.cs | ||
---|---|---|
2 | 2 |
|
3 | 3 |
namespace RestAPI.Utils; |
4 | 4 |
|
5 |
/// <summary> |
|
6 |
/// Request client information |
|
7 |
/// </summary> |
|
5 | 8 |
public class ClientInfo |
6 | 9 |
{ |
7 | 10 |
public bool IsLogged => LoggedUser != null; |
8 |
|
|
9 | 11 |
public User? LoggedUser { get; set; } = null; |
10 |
|
|
11 | 12 |
public string IP { get; set; } = "unknown"; |
12 | 13 |
} |
Backend/Backend/Utils/ContextUtils.cs | ||
---|---|---|
18 | 18 |
} |
19 | 19 |
} |
20 | 20 |
|
21 |
/// <summary> |
|
22 |
/// Exctracts client information given HttpContext |
|
23 |
/// </summary> |
|
24 |
/// <param name="context"></param> |
|
25 |
/// <returns></returns> |
|
21 | 26 |
public static ClientInfo GetClientInfo(HttpContext? context) |
22 | 27 |
{ |
23 | 28 |
var ci = new ClientInfo(); |
Backend/Core/Authentication/JwtUtils.cs | ||
---|---|---|
16 | 16 |
|
17 | 17 |
public class JwtUtils : IJwtUtils |
18 | 18 |
{ |
19 |
private const int EXPIRATION_SECONDS = 8 * 60 * 60; // 8 hod
|
|
19 |
private const int EXPIRATION_SECONDS = 8 * 60 * 60; // 8 hrs
|
|
20 | 20 |
|
21 | 21 |
private readonly JwtConfig _jwtConfig; |
22 | 22 |
private readonly TokenValidationParameters _tokenValidationParameters; |
Backend/Core/Constants/Constants.cs | ||
---|---|---|
8 | 8 |
{ |
9 | 9 |
public class Constants |
10 | 10 |
{ |
11 |
/// <summary> |
|
12 |
/// Key for RequiredAnnotation value in database |
|
13 |
/// </summary> |
|
11 | 14 |
public static string RequiredAnnotationsKey { get; } = "RequiredAnnotations"; |
12 | 15 |
} |
13 | 16 |
} |
Backend/Core/Contexts/DatabaseContext.cs | ||
---|---|---|
35 | 35 |
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) |
36 | 36 |
{ |
37 | 37 |
optionsBuilder.UseNpgsql(_configuration["ConnectionString"], b => b.MigrationsAssembly("RestAPI")); |
38 |
//optionsBuilder.UseNpgsql("Host=localhost:5432;Database=dbo;Username=myuser;Password=password"); |
|
39 |
} |
|
40 |
|
|
41 |
protected override void OnModelCreating(ModelBuilder modelBuilder) |
|
42 |
{ |
|
43 | 38 |
} |
44 | 39 |
} |
45 | 40 |
} |
Backend/Core/Entities/Annotation.cs | ||
---|---|---|
11 | 11 |
{ |
12 | 12 |
public class Annotation : BaseEntity |
13 | 13 |
{ |
14 |
/*[ForeignKey("Document")] |
|
15 |
public int DocumentId { get; set; }*/ |
|
14 |
/// <summary> |
|
15 |
/// Document that the annotation refers to |
|
16 |
/// </summary> |
|
16 | 17 |
public Document Document { get; set; } |
17 | 18 |
|
18 |
/*[ForeignKey("User")] |
|
19 |
public int UserId { get; set; }*/ |
|
19 |
/// <summary> |
|
20 |
/// User the annotation is assigned to |
|
21 |
/// </summary> |
|
20 | 22 |
public User User { get; set; } |
21 | 23 |
|
22 |
/*[ForeignKey("User")] |
|
23 |
public int UserAssignedId { get; set; }*/ |
|
24 |
/// <summary> |
|
25 |
/// The user that assigned the annotation |
|
26 |
/// </summary> |
|
24 | 27 |
public User UserAssigned { get; set; } |
25 | 28 |
|
29 |
/// <summary> |
|
30 |
/// The date the annotation was assigned |
|
31 |
/// </summary> |
|
26 | 32 |
public DateTime DateAssigned { get; set; } |
33 |
|
|
34 |
/// <summary> |
|
35 |
/// The state of the annotation |
|
36 |
/// </summary> |
|
27 | 37 |
public EState State { get; set; } |
38 |
|
|
39 |
/// <summary> |
|
40 |
/// The date the annotation was last modified |
|
41 |
/// </summary> |
|
28 | 42 |
public DateTime DateLastChanged { get; set; } |
43 |
|
|
44 |
/// <summary> |
|
45 |
/// Annotation note |
|
46 |
/// </summary> |
|
29 | 47 |
public string Note { get; set; } = ""; |
30 | 48 |
|
49 |
//Cached information START |
|
31 | 50 |
public string CachedDocumentHTML { get; set; } = ""; |
32 | 51 |
public string CachedStartPositions { get; set; } = ""; |
33 | 52 |
public string CachedLengths { get; set; } = ""; |
34 | 53 |
public string CachedClosingPositions { get; set; } = ""; |
35 | 54 |
public string CachedClosingLengths { get; set; } = ""; |
36 | 55 |
public string CachedCSS { get; set; } = ""; |
56 |
//Cached information END |
|
37 | 57 |
|
58 |
/// <summary> |
|
59 |
/// ID of the last modified tag |
|
60 |
/// </summary> |
|
38 | 61 |
public Guid? LastModifiedTagId { get; set; } |
62 |
|
|
63 |
/// <summary> |
|
64 |
/// The modification that is done |
|
65 |
/// </summary> |
|
39 | 66 |
public EModified ModifiedType { get; set; } = EModified.NONE; |
40 | 67 |
|
68 |
/// <summary> |
|
69 |
/// Unused |
|
70 |
/// </summary> |
|
41 | 71 |
public ICollection<Class> Classes { get; set; } = new List<Class>(); |
42 | 72 |
|
73 |
/// <summary> |
|
74 |
/// So that EF creates a join table as 1 final annotation to N annotations |
|
75 |
/// </summary> |
|
76 |
|
|
43 | 77 |
public ICollection<FinalAnnotation> FinalAnnotations { get; set; } = new List<FinalAnnotation>(); |
44 | 78 |
} |
45 | 79 |
} |
Backend/Core/Entities/AnnotationTag.cs | ||
---|---|---|
11 | 11 |
{ |
12 | 12 |
public class AnnotationTag : AnnotationTagGeneric |
13 | 13 |
{ |
14 |
/// <summary> |
|
15 |
/// The annotation the annotation tag is linked to |
|
16 |
/// </summary> |
|
14 | 17 |
public Annotation Annotation { get; set; } |
15 | 18 |
} |
16 | 19 |
} |
Backend/Core/Entities/AnnotationTagGeneric.cs | ||
---|---|---|
7 | 7 |
|
8 | 8 |
namespace Core.Entities |
9 | 9 |
{ |
10 |
/// <summary> |
|
11 |
/// Base class for tag occurences in annotations |
|
12 |
/// </summary> |
|
10 | 13 |
public class AnnotationTagGeneric : BaseEntity |
11 | 14 |
{ |
15 |
/// <summary> |
|
16 |
/// Tag |
|
17 |
/// </summary> |
|
12 | 18 |
public Tag Tag { get; set; } |
13 | 19 |
|
14 |
/** Nullable for optional */ |
|
20 |
/// <summary> |
|
21 |
/// Subtag, nulllable for optional |
|
22 |
/// </summary> |
|
15 | 23 |
public SubTag? SubTag { get; set; } |
16 | 24 |
|
25 |
/// <summary> |
|
26 |
/// Id of the instance (shared by multipart tags) |
|
27 |
/// </summary> |
|
17 | 28 |
public Guid Instance { get; set; } |
29 |
|
|
30 |
/// <summary> |
|
31 |
/// The tag note |
|
32 |
/// </summary> |
|
18 | 33 |
public string Note { get; set; } |
19 | 34 |
public int Position { get; set; } |
20 | 35 |
public int Length { get; set; } |
36 |
|
|
37 |
/// <summary> |
|
38 |
/// Sentiment of the tag, nullable for optional |
|
39 |
/// </summary> |
|
21 | 40 |
public ETagSentiment? Sentiment { get; set; } |
41 |
|
|
42 |
/// <summary> |
|
43 |
/// The text that the tag is covering |
|
44 |
/// </summary> |
|
22 | 45 |
public string SelectedText { get; set; } |
23 | 46 |
} |
24 | 47 |
} |
Backend/Core/Entities/BaseEntity.cs | ||
---|---|---|
7 | 7 |
|
8 | 8 |
namespace Core.Entities |
9 | 9 |
{ |
10 |
/// <summary> |
|
11 |
/// Base entity, defines the ID |
|
12 |
/// </summary> |
|
10 | 13 |
public class BaseEntity |
11 | 14 |
{ |
12 | 15 |
[Key] |
Backend/Core/Entities/Class.cs | ||
---|---|---|
7 | 7 |
|
8 | 8 |
namespace Core.Entities |
9 | 9 |
{ |
10 |
/// <summary> |
|
11 |
/// Unused |
|
12 |
/// </summary> |
|
10 | 13 |
public class Class : BaseEntity |
11 | 14 |
{ |
12 | 15 |
public string Name { get; set; } |
Backend/Core/Entities/ConfigurationItem.cs | ||
---|---|---|
6 | 6 |
|
7 | 7 |
namespace Core.Entities |
8 | 8 |
{ |
9 |
/// <summary> |
|
10 |
/// Configuration for the key-value database storage |
|
11 |
/// </summary> |
|
9 | 12 |
public class ConfigurationItem : BaseEntity |
10 | 13 |
{ |
11 | 14 |
public string Value { get; set; } |
Backend/Core/Entities/Document.cs | ||
---|---|---|
11 | 11 |
#nullable disable |
12 | 12 |
public class Document : BaseEntity |
13 | 13 |
{ |
14 |
/// <summary> |
|
15 |
/// Document name |
|
16 |
/// </summary> |
|
14 | 17 |
public string Name { get; set; } |
18 |
|
|
19 |
/// <summary> |
|
20 |
/// Length in characters |
|
21 |
/// </summary> |
|
15 | 22 |
public int Length { get; set; } |
16 | 23 |
|
24 |
/// <summary> |
|
25 |
/// Actual content |
|
26 |
/// </summary> |
|
17 | 27 |
public DocumentContent Content { get; set; } |
18 | 28 |
|
29 |
/// <summary> |
|
30 |
/// Date added |
|
31 |
/// </summary> |
|
19 | 32 |
public DateTime DateAdded { get; set; } |
20 | 33 |
|
34 |
/// <summary> |
|
35 |
/// User who added it |
|
36 |
/// </summary> |
|
21 | 37 |
public User UserAdded { get; set; } |
22 | 38 |
|
39 |
/// <summary> |
|
40 |
/// Number of required annotations |
|
41 |
/// </summary> |
|
23 | 42 |
public int RequiredAnnotations { get; set; } |
24 | 43 |
} |
25 | 44 |
} |
Backend/Core/Entities/DocumentContent.cs | ||
---|---|---|
10 | 10 |
{ |
11 | 11 |
public class DocumentContent : BaseEntity |
12 | 12 |
{ |
13 |
/// <summary> |
|
14 |
/// String with the document content |
|
15 |
/// </summary> |
|
13 | 16 |
public string Content { get; set; } |
14 | 17 |
} |
15 | 18 |
} |
Backend/Core/Entities/FinalAnnotation.cs | ||
---|---|---|
9 | 9 |
{ |
10 | 10 |
public class FinalAnnotation : Annotation |
11 | 11 |
{ |
12 |
/// <summary> |
|
13 |
/// List of annotations that were used to create the final annotation |
|
14 |
/// </summary> |
|
12 | 15 |
public List<Annotation> Annotations { get; set; } = new(); |
13 | 16 |
} |
14 | 17 |
} |
Backend/Core/Entities/FinalAnnotationTag.cs | ||
---|---|---|
8 | 8 |
{ |
9 | 9 |
public class FinalAnnotationTag : AnnotationTagGeneric |
10 | 10 |
{ |
11 |
/// <summary> |
|
12 |
/// FinalAnnotation the tag is linked to |
|
13 |
/// </summary> |
|
11 | 14 |
public FinalAnnotation Annotation { get; set; } |
15 |
|
|
16 |
/// <summary> |
|
17 |
/// Whether the tag is marked as final or not |
|
18 |
/// </summary> |
|
12 | 19 |
public bool IsFinal { get; set; } = false; |
20 |
|
|
21 |
/// <summary> |
|
22 |
/// List of users who have agreed on this tag |
|
23 |
/// </summary> |
|
13 | 24 |
public ICollection<User> Users { get; set; } = new List<User>(); |
14 | 25 |
} |
15 | 26 |
} |
Backend/Core/Entities/SubTag.cs | ||
---|---|---|
12 | 12 |
public string Name { get; set; } |
13 | 13 |
public string Description { get; set; } |
14 | 14 |
public Tag Tag { get; set; } |
15 |
|
|
16 |
/// <summary> |
|
17 |
/// Whether or not this tag supports sentiment |
|
18 |
/// </summary> |
|
15 | 19 |
public bool SentimentEnabled { get; set; } = false; |
16 | 20 |
} |
17 | 21 |
} |
Backend/Core/Entities/Tag.cs | ||
---|---|---|
14 | 14 |
public string Name { get; set; } |
15 | 15 |
public string Description { get; set; } |
16 | 16 |
public string Color { get; set; } |
17 |
|
|
18 |
/// <summary> |
|
19 |
/// Whether or not this tag supports sentiment |
|
20 |
/// </summary> |
|
17 | 21 |
public bool SentimentEnabled { get; set; } = false; |
18 | 22 |
} |
19 | 23 |
} |
Backend/Core/Entities/TagCategory.cs | ||
---|---|---|
13 | 13 |
public string Name { get; set; } |
14 | 14 |
public string Color { get; set; } |
15 | 15 |
public string Description { get; set; } |
16 |
|
|
17 |
/// <summary> |
|
18 |
/// Whether or not this category is only visible to admins |
|
19 |
/// </summary> |
|
16 | 20 |
public bool DisabledForAnnotators { get; set; } = false; |
17 | 21 |
} |
18 | 22 |
} |
Backend/Core/Entities/User.cs | ||
---|---|---|
21 | 21 |
|
22 | 22 |
public ERole Role { get; set; } |
23 | 23 |
|
24 |
/// <summary> |
|
25 |
/// Force EF to create a join table |
|
26 |
/// </summary> |
|
24 | 27 |
public ICollection<FinalAnnotationTag> FinalAnnotationTags { get; set; } = new List<FinalAnnotationTag>(); |
25 | 28 |
} |
26 | 29 |
} |
Backend/Core/GraphUtils/Intersections.cs | ||
---|---|---|
4 | 4 |
{ |
5 | 5 |
public class Intersections |
6 | 6 |
{ |
7 |
/// <summary> |
|
8 |
/// Finds intersections between 1D segments |
|
9 |
/// </summary> |
|
10 |
/// <param name="tags"></param> |
|
11 |
/// <returns></returns> |
|
7 | 12 |
public static Dictionary<AnnotationTagGeneric, List<AnnotationTagGeneric>> FindIntersections(List<AnnotationTagGeneric> tags) |
8 | 13 |
{ |
9 | 14 |
var intersections = new Dictionary<AnnotationTagGeneric, List<AnnotationTagGeneric>>(); |
... | ... | |
27 | 32 |
return intersections; |
28 | 33 |
} |
29 | 34 |
|
35 |
/// <summary> |
|
36 |
/// Graph coloring |
|
37 |
/// </summary> |
|
38 |
/// <param name="source"></param> |
|
39 |
/// <returns></returns> |
|
30 | 40 |
public static Dictionary<AnnotationTagGeneric, int> ColorGraph(Dictionary<AnnotationTagGeneric, List<AnnotationTagGeneric>> source) |
31 | 41 |
{ |
32 | 42 |
var res = ConvertToMatrix(source); |
Backend/Core/MapperProfiles/DocumentProfileEF.cs | ||
---|---|---|
14 | 14 |
public DocumentProfileEF() |
15 | 15 |
{ |
16 | 16 |
CreateMap<Document, DocumentListInfo>(); |
17 |
/*.ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Id)) |
|
18 |
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name)) |
|
19 |
.ForMember(dest => dest.Length, opt => opt.MapFrom(src => src.Length)) |
|
20 |
.ForMember(dest => dest.RequiredAnnotations, opt => opt.MapFrom(src => src.RequiredAnnotations));*/ |
|
21 |
|
|
22 | 17 |
} |
23 | 18 |
} |
24 | 19 |
} |
Backend/Core/MapperProfiles/RegisterMappings.cs | ||
---|---|---|
11 | 11 |
{ |
12 | 12 |
public class RegisterMappings |
13 | 13 |
{ |
14 |
/// <summary> |
|
15 |
/// Registers mappings for AutoMapper in DI |
|
16 |
/// </summary> |
|
17 |
/// <param name="builder"></param> |
|
14 | 18 |
public static void Register(WebApplicationBuilder builder) |
15 | 19 |
{ |
16 |
builder.Services.AddAutoMapper(typeof(UserProfileEF), typeof(DocumentProfileEF)); |
|
20 |
builder.Services.AddAutoMapper(typeof(UserProfileEF), typeof(DocumentProfileEF), typeof(TagProfileEF));
|
|
17 | 21 |
} |
18 | 22 |
} |
19 | 23 |
} |
Backend/Core/Services/AnnotationService/IAnnotationService.cs | ||
---|---|---|
11 | 11 |
{ |
12 | 12 |
public interface IAnnotationService |
13 | 13 |
{ |
14 |
/// <summary> |
|
15 |
/// Assign users to documents |
|
16 |
/// </summary> |
|
17 |
/// <param name="request"></param> |
|
18 |
/// <param name="userId"></param> |
|
14 | 19 |
public void CreateDocumentAnnotations(AnnotationsAddRequest request, Guid userId); |
20 |
/// <summary> |
|
21 |
/// Given user, return their annotations |
|
22 |
/// </summary> |
|
23 |
/// <param name="userId"></param> |
|
24 |
/// <returns></returns> |
|
15 | 25 |
public AnnotationListResponse GetUserAnnotations(Guid userId); |
26 |
/// <summary> |
|
27 |
/// Return given annotation |
|
28 |
/// </summary> |
|
29 |
/// <param name="annotationId"></param> |
|
30 |
/// <param name="userId"></param> |
|
31 |
/// <param name="userRole"></param> |
|
32 |
/// <param name="isFinal">is it final annotation or standard annotation</param> |
|
33 |
/// <returns></returns> |
|
16 | 34 |
public AnnotationInfo GetAnnotation(Guid annotationId, Guid userId, ERole userRole, bool isFinal); |
35 |
/// <summary> |
|
36 |
/// Adds a tag to an annotation |
|
37 |
/// </summary> |
|
38 |
/// <param name="annotationId"></param> |
|
39 |
/// <param name="userId"></param> |
|
40 |
/// <param name="userRole"></param> |
|
41 |
/// <param name="request"></param> |
|
42 |
/// <param name="isFinal">is it final annotation or standard annotation</param> |
|
17 | 43 |
public void AddAnnotationInstance(Guid annotationId, Guid userId, ERole userRole, AnnotationInstanceAddRequest request, bool isFinal); |
44 |
/// <summary> |
|
45 |
/// Remove a tag from annotation |
|
46 |
/// </summary> |
|
47 |
/// <param name="annotationId"></param> |
|
48 |
/// <param name="tagInstanceId"></param> |
|
49 |
/// <param name="loggedUserId"></param> |
|
50 |
/// <param name="userRole"></param> |
|
51 |
/// <param name="isFinal">is it final annotation or standard annotation</param> |
|
18 | 52 |
public void DeleteAnnotationInstance(Guid annotationId, Guid tagInstanceId, Guid loggedUserId, ERole userRole, bool isFinal); |
53 |
/// <summary> |
|
54 |
/// Add note to annotation |
|
55 |
/// </summary> |
|
56 |
/// <param name="annotationId"></param> |
|
57 |
/// <param name="userId"></param> |
|
58 |
/// <param name="userRole"></param> |
|
59 |
/// <param name="request"></param> |
|
60 |
/// <param name="isFinal">is it final annotation or standard annotation</param> |
|
19 | 61 |
public void AddNoteToAnnotation(Guid annotationId, Guid userId, ERole userRole, AddNoteToAnnotationRequest request, bool isFinal); |
62 |
/// <summary> |
|
63 |
/// Set sentiment of a tag |
|
64 |
/// </summary> |
|
65 |
/// <param name="annotationId"></param> |
|
66 |
/// <param name="instanceId"></param> |
|
67 |
/// <param name="userId"></param> |
|
68 |
/// <param name="userRole"></param> |
|
69 |
/// <param name="sentiment"></param> |
|
70 |
/// <param name="isFinal">is it final annotation or standard annotation</param> |
|
20 | 71 |
public void SetTagInstanceSentiment(Guid annotationId, Guid instanceId, Guid userId, ERole userRole, ETagSentiment sentiment, bool isFinal); |
72 |
/// <summary> |
|
73 |
/// Set the annotation state to DONE or IN_PROGRESS |
|
74 |
/// </summary> |
|
75 |
/// <param name="annotationId"></param> |
|
76 |
/// <param name="userId"></param> |
|
77 |
/// <param name="userRole"></param> |
|
78 |
/// <param name="done">is it DONE or not</param> |
|
79 |
/// <param name="isFinal"is it final annotation or standard annotation></param> |
|
21 | 80 |
public void MarkAnnotationAsDone(Guid annotationId, Guid userId, ERole userRole, bool done, bool isFinal); |
81 |
/// <summary> |
|
82 |
/// Creates a final annotation |
|
83 |
/// </summary> |
|
84 |
/// <param name="documentId"></param> |
|
85 |
/// <param name="userId"></param> |
|
86 |
/// <returns>ID of the final annotation</returns> |
|
22 | 87 |
public Guid CreateFinalAnnotation(Guid documentId, Guid userId); |
88 |
/// <summary> |
|
89 |
/// Performs an export |
|
90 |
/// </summary> |
|
91 |
/// <param name="request"></param> |
|
92 |
/// <returns>ZIP memory stream</returns> |
|
23 | 93 |
public MemoryStream Export(ExportRequest request); |
94 |
/// <summary> |
|
95 |
/// Marks tag as final |
|
96 |
/// </summary> |
|
97 |
/// <param name="annotationId"></param> |
|
98 |
/// <param name="occurenceId"></param> |
|
99 |
/// <param name="isFinal">is the tag final or not</param> |
|
24 | 100 |
public void SetTagIsFinal(Guid annotationId, Guid occurenceId, bool isFinal); |
25 | 101 |
} |
26 | 102 |
} |
Backend/Core/Services/AuthService/IAuthService.cs | ||
---|---|---|
5 | 5 |
|
6 | 6 |
public interface IAuthService |
7 | 7 |
{ |
8 |
/// <summary> |
|
9 |
/// Check username and password |
|
10 |
/// </summary> |
|
11 |
/// <param name="username"></param> |
|
12 |
/// <param name="password"></param> |
|
13 |
/// <returns></returns> |
|
8 | 14 |
public LoginResponse? Login(string username, string password); |
9 | 15 |
} |
Backend/Core/Services/DocumentService/DocumentServiceEF.cs | ||
---|---|---|
63 | 63 |
} |
64 | 64 |
|
65 | 65 |
/// <summary> |
66 |
/// |
|
66 |
/// Process a zip file and returns a list of names and documents
|
|
67 | 67 |
/// </summary> |
68 | 68 |
/// <param name="base64encoded"></param> |
69 | 69 |
/// <returns></returns> |
... | ... | |
91 | 91 |
return (names, contents); |
92 | 92 |
} |
93 | 93 |
|
94 |
/// <summary> |
|
95 |
/// Save a document in the database |
|
96 |
/// </summary> |
|
97 |
/// <param name="content"></param> |
|
98 |
/// <param name="userAdded"></param> |
|
99 |
/// <param name="documentName"></param> |
|
100 |
/// <param name="requiredAnnotations"></param> |
|
94 | 101 |
private void SaveDocument(string content, User userAdded, string documentName, int requiredAnnotations) |
95 | 102 |
{ |
96 | 103 |
DocumentContent documentContent = new DocumentContent() |
... | ... | |
140 | 147 |
} |
141 | 148 |
|
142 | 149 |
DocumentListInfo dli = mapper.Map<DocumentListInfo>(document); |
150 |
// Add list of users taht annotate the document |
|
143 | 151 |
dli.AnnotatingUsers = annotatingUsersDto; |
144 | 152 |
|
153 |
// Add info about the finalized version |
|
145 | 154 |
dli.FinalizedExists = databaseContext.FinalAnnotations.Any(fa => fa.Document == document); |
146 | 155 |
if (dli.FinalizedExists) |
147 | 156 |
{ |
... | ... | |
154 | 163 |
dli.FinalizedState = finalizedAnnotation.State; |
155 | 164 |
dli.FinalAnnotations = new(); |
156 | 165 |
|
166 |
// Add information about which annotations were used to create the finalized version |
|
157 | 167 |
foreach (var annotation in finalizedAnnotation.Annotations) |
158 | 168 |
{ |
159 | 169 |
dli.FinalAnnotations.Add(new() |
Backend/Core/Services/DocumentService/IDocumentService.cs | ||
---|---|---|
11 | 11 |
{ |
12 | 12 |
public interface IDocumentService |
13 | 13 |
{ |
14 |
/// <summary> |
|
15 |
/// Add list of documents to a list of users |
|
16 |
/// </summary> |
|
17 |
/// <param name="request"></param> |
|
18 |
/// <param name="userId"></param> |
|
14 | 19 |
public void AddDocuments(DocumentAddRequest request, Guid userId); |
20 |
/// <summary> |
|
21 |
/// Returns all documents |
|
22 |
/// </summary> |
|
23 |
/// <returns></returns> |
|
15 | 24 |
public DocumentListResponse GetDocuments(); |
25 |
/// <summary> |
|
26 |
/// Returns a preview of a document (HTML) |
|
27 |
/// </summary> |
|
28 |
/// <param name="documentId"></param> |
|
29 |
/// <returns></returns> |
|
16 | 30 |
public DocumentPreviewResponse GetDocumentPreview(Guid documentId); |
31 |
/// <summary> |
|
32 |
/// Delete a list of documents |
|
33 |
/// </summary> |
|
34 |
/// <param name="request"></param> |
|
17 | 35 |
public void DeleteDocuments(DeleteDocumentsRequest request); |
36 |
/// <summary> |
|
37 |
/// Set required number of annotations for a list of documents |
|
38 |
/// </summary> |
|
39 |
/// <param name="request"></param> |
|
18 | 40 |
public void SetRequiredAnnotationsForDocuments(SetRequiredAnnotationsRequest request); |
41 |
/// <summary> |
|
42 |
/// Set default required number of annotations |
|
43 |
/// </summary> |
|
44 |
/// <param name="requiredAnnotations"></param> |
|
19 | 45 |
public void SetRequiredAnnotationsGlobal(int requiredAnnotations); |
46 |
/// <summary> |
|
47 |
/// Get default required number of annotations |
|
48 |
/// </summary> |
|
49 |
/// <returns></returns> |
|
20 | 50 |
public int GetRequiredAnnotationsGlobal(); |
51 |
/// <summary> |
|
52 |
/// Remove an annotator from a document |
|
53 |
/// </summary> |
|
54 |
/// <param name="documentId"></param> |
|
55 |
/// <param name="annotatorId"></param> |
|
21 | 56 |
public void RemoveAnnotatorFromDocument(Guid documentId, Guid annotatorId); |
22 | 57 |
} |
23 | 58 |
} |
Backend/Core/Services/HTMLService/HTMLService.cs | ||
---|---|---|
13 | 13 |
{ |
14 | 14 |
public class HTMLService : IHTMLService |
15 | 15 |
{ |
16 |
|
|
16 |
/// <summary> |
|
17 |
/// Attribute name for uniquely identifying each tag in the HTML document on the frontend |
|
18 |
/// </summary> |
|
17 | 19 |
private const string TAG_ID_ATTRIBUTE_NAME = "aswi-tag-id"; |
20 |
|
|
21 |
/// <summary> |
|
22 |
/// Attribute name for tag instance so that each marked out tag can be given a style |
|
23 |
/// </summary> |
|
18 | 24 |
private const string TAG_INSTANCE_ATTRIBUTE_NAME = "aswi-tag-instance"; |
25 |
|
|
26 |
/// <summary> |
|
27 |
/// Attribute name for EF Tag IDs so that the frontend can reference them to the backend for deletion |
|
28 |
/// </summary> |
|
19 | 29 |
private const string TAG_EF_ID_ATTRIBUTE_NAME = "aswi-tag-ef-id"; |
20 | 30 |
|
31 |
/// <summary> |
|
32 |
/// Info that is cached in tha database |
|
33 |
/// </summary> |
|
21 | 34 |
public class CachedInfo |
22 | 35 |
{ |
36 |
/// <summary> |
|
37 |
/// Positions of opening tags in the original HTML document |
|
38 |
/// </summary> |
|
23 | 39 |
public List<int> TagStartPositions = new(); |
40 |
/// <summary> |
|
41 |
/// Lengths of opening tags in the original HTML document |
|
42 |
/// </summary> |
|
24 | 43 |
public List<int> TagStartLengths = new(); |
44 |
/// <summary> |
|
45 |
/// Positions of closing tags in the original HTML document |
|
46 |
/// </summary> |
|
25 | 47 |
public List<int> TagClosingPositions = new(); |
48 |
/// <summary> |
|
49 |
/// Lengths for closing tags in the original HTML document |
|
50 |
/// </summary> |
|
26 | 51 |
public List<int> TagClosingLengths = new(); |
52 |
/// <summary> |
|
53 |
/// Unused |
|
54 |
/// </summary> |
|
27 | 55 |
public Dictionary<HtmlNode, HtmlNode> NodeDict = new(); |
56 |
/// <summary> |
|
57 |
/// Cached CSS for each tag |
|
58 |
/// </summary> |
|
28 | 59 |
public List<TagInstanceCSSInfo> TagInstanceCSS = new(); |
29 | 60 |
} |
30 | 61 |
|
... | ... | |
35 | 66 |
private Dictionary<HtmlNode, HtmlNode> NodeDict = new(); |
36 | 67 |
private List<TagInstanceCSSInfo> TagInstanceCSS = new(); |
37 | 68 |
|
69 |
/// <summary> |
|
70 |
/// Unpack cached info into local (request-scoped) variables |
|
71 |
/// </summary> |
|
72 |
/// <param name="cachedInfo"></param> |
|
38 | 73 |
private void UnpackCachedInfo(CachedInfo cachedInfo) |
39 | 74 |
{ |
40 | 75 |
TagStartPositions = cachedInfo.TagStartPositions; |
... | ... | |
62 | 97 |
|
63 | 98 |
int currentId = 0; |
64 | 99 |
|
100 |
// Create mapping original-document-node -> to-edit-document-node |
|
65 | 101 |
FillNodeDict(descendantsOriginal, descendantsToEdit); |
102 |
|
|
103 |
// Assign IDs to all original rtags |
|
66 | 104 |
AssignIdsToOriginalDocument(descendantsOriginal, ref currentId); |
67 | 105 |
|
106 |
// Wrap all text that is not in a tag or where the parent node contains tags as children also in spans |
|
68 | 107 |
WrapTextInSpan(descendantsOriginal, docToEdit); |
69 | 108 |
|
70 | 109 |
descendantsToEdit = docToEdit.DocumentNode.DescendantsAndSelf().ToList(); |
... | ... | |
156 | 195 |
}); |
157 | 196 |
} |
158 | 197 |
|
198 |
/// <summary> |
|
199 |
/// Wrap text in span when the target text is the whole text of the target tag |
|
200 |
/// </summary> |
|
201 |
/// <param name="node">text node to wrap</param> |
|
202 |
/// <param name="selectionStart">start of the selection in the edited document</param> |
|
203 |
/// <param name="selectionEnd">end of the selection in the edited document</param> |
|
204 |
/// <param name="start">start of the node</param> |
|
205 |
/// <param name="end">end of the node</param> |
|
206 |
/// <param name="docToEdit">document to edit</param> |
|
207 |
/// <param name="tag">tag we are adding</param> |
|
208 |
/// <returns></returns> |
|
159 | 209 |
private HtmlNode SolveFullFill(HtmlNode node, int selectionStart, int selectionEnd, int start, int end, HtmlDocument docToEdit, AnnotationTagGeneric tag) |
160 | 210 |
{ |
161 | 211 |
// full fill |
... | ... | |
185 | 235 |
return spanSelected; |
186 | 236 |
} |
187 | 237 |
|
238 |
/// <summary> |
|
239 |
/// Wrap text in span when the target text starts at the start of the tag and leaves space on the right side |
|
240 |
/// </summary> |
|
241 |
/// <param name="node">text node to wrap</param> |
|
242 |
/// <param name="selectionStart">start of the selection in the edited document</param> |
|
243 |
/// <param name="selectionEnd">end of the selection in the edited document</param> |
|
244 |
/// <param name="start">start of the node</param> |
|
245 |
/// <param name="end">end of the node</param> |
|
246 |
/// <param name="docToEdit">document to edit</param> |
|
247 |
/// <param name="tag">tag we are adding</param> |
|
248 |
/// <returns></returns> |
|
188 | 249 |
private List<HtmlNode> SolveRightGap(HtmlNode node, int selectionStart, int selectionEnd, int start, int end, HtmlDocument docToEdit, |
189 | 250 |
AnnotationTagGeneric tag) |
190 | 251 |
{ |
... | ... | |
215 | 276 |
return new() { spanSelected, spanAfter }; |
216 | 277 |
} |
217 | 278 |
|
279 |
/// <summary> |
|
280 |
/// Wrap text in span when the target text ends at the end of the tag but leaves space on the left |
|
281 |
/// </summary> |
|
282 |
/// <param name="node">text node to wrap</param> |
|
283 |
/// <param name="selectionStart">start of the selection in the edited document</param> |
|
284 |
/// <param name="selectionEnd">end of the selection in the edited document</param> |
|
285 |
/// <param name="start">start of the node</param> |
|
286 |
/// <param name="end">end of the node</param> |
|
287 |
/// <param name="docToEdit">document to edit</param> |
|
288 |
/// <param name="tag">tag we are adding</param> |
|
289 |
/// <returns></returns> |
|
218 | 290 |
private List<HtmlNode> SolveLeftGap(HtmlNode node, int selectionStart, int selectionEnd, int start, int end, HtmlDocument docToEdit, |
219 | 291 |
AnnotationTagGeneric tag) |
220 | 292 |
{ |
... | ... | |
245 | 317 |
return new() { spanSelected, spanBefore }; |
246 | 318 |
} |
247 | 319 |
|
320 |
/// <summary> |
|
321 |
/// Wrap text in span when the target text is contained in the node but neither starts or ends match |
|
322 |
/// </summary> |
|
323 |
/// <param name="node">text node to wrap</param> |
|
324 |
/// <param name="selectionStart">start of the selection in the edited document</param> |
|
325 |
/// <param name="selectionEnd">end of the selection in the edited document</param> |
|
326 |
/// <param name="start">start of the node</param> |
|
327 |
/// <param name="end">end of the node</param> |
|
328 |
/// <param name="docToEdit">document to edit</param> |
|
329 |
/// <param name="tag">tag we are adding</param> |
|
330 |
/// <returns></returns> |
|
248 | 331 |
private List<HtmlNode> SolveLeftRightGap(HtmlNode node, int selectionStart, int selectionEnd, int start, int end, HtmlDocument docToEdit, |
249 | 332 |
AnnotationTagGeneric tag) |
250 | 333 |
{ |
... | ... | |
274 | 357 |
return new() { spanSelected, spanBefore, spanAfter }; |
275 | 358 |
} |
276 | 359 |
|
360 |
/// <summary> |
|
361 |
/// Create span utility method |
|
362 |
/// </summary> |
|
363 |
/// <param name="doc">document</param> |
|
364 |
/// <param name="text">inner text of the span</param> |
|
365 |
/// <param name="tagId">ID of the tag (TAG_ID_ATTRIBUTE_NAME)</param> |
|
366 |
/// <param name="instanceId">ID of the instance (TAG_INSTANCE_ATTRIBUTE_NAME)</param> |
|
367 |
/// <param name="entityId">Id of the EF entity (TAG_EF_ID_NAME)</param> |
|
368 |
/// <param name="startPosition"></param> |
|
369 |
/// <param name="position"></param> |
|
370 |
/// <returns></returns> |
|
277 | 371 |
private HtmlNode CreateSpan(HtmlDocument doc, string text, int tagId, Guid? instanceId, Guid? entityId, int startPosition, EPosition position = EPosition.MARK_NONE) |
278 | 372 |
{ |
279 | 373 |
HtmlNode span = doc.CreateElement("span"); |
... | ... | |
312 | 406 |
MARK_NONE = 0 |
313 | 407 |
} |
314 | 408 |
|
409 |
/// <summary> |
|
410 |
/// Redirect all links |
|
411 |
/// </summary> |
|
412 |
/// <param name="descendantsOriginal"></param> |
|
315 | 413 |
private void ModifyLinks(IEnumerable<HtmlNode> descendantsOriginal) |
316 | 414 |
{ |
317 | 415 |
foreach (var descendant in descendantsOriginal) |
... | ... | |
327 | 425 |
} |
328 | 426 |
} |
329 | 427 |
|
428 |
/// <summary> |
|
429 |
/// Wrap all #text nodes in spans |
|
430 |
/// </summary> |
|
431 |
/// <param name="descendantsOriginal"></param> |
|
432 |
/// <param name="docToEdit"></param> |
|
330 | 433 |
private void WrapTextInSpan(IEnumerable<HtmlNode> descendantsOriginal, HtmlDocument docToEdit) |
331 | 434 |
{ |
332 | 435 |
// Special case for non-html documents |
... | ... | |
389 | 492 |
foreach (var child in node.ChildNodes) |
390 | 493 |
{ |
391 | 494 |
if (child.Name.Contains("#text")) |
392 |
{ |
|
495 |
{
|
|
393 | 496 |
HtmlNode coveringSpan = docToEdit.CreateElement("span"); |
394 | 497 |
coveringSpan.InnerHtml = child.InnerHtml; |
498 |
|
|
499 |
// Add length of 0 - in they were not in the original document |
|
395 | 500 |
TagStartPositions.Add(child.InnerStartIndex); |
396 | 501 |
TagStartLengths.Add(0); |
397 | 502 |
TagClosingPositions.Add(child.InnerStartIndex + child.InnerLength); |
... | ... | |
410 | 515 |
} |
411 | 516 |
} |
412 | 517 |
|
518 |
/// <summary> |
|
519 |
/// Generate CSS for all tag instances |
|
520 |
/// </summary> |
|
521 |
/// <param name="tags"></param> |
|
413 | 522 |
private void GenerateCSS(List<AnnotationTagGeneric> tags) |
414 | 523 |
{ |
415 | 524 |
/*string inner = "span.annotation {border-bottom: 2px solid;}"; |
... | ... | |
428 | 537 |
} |
429 | 538 |
} |
430 | 539 |
|
540 |
/// <summary> |
|
541 |
/// Add IDs to all tags in the original document |
|
542 |
/// </summary> |
|
543 |
/// <param name="descendantsOriginal"></param> |
|
544 |
/// <param name="currentId"></param> |
|
431 | 545 |
private void AssignIdsToOriginalDocument(IEnumerable<HtmlNode> descendantsOriginal, ref int currentId) |
432 | 546 |
{ |
433 | 547 |
foreach (var node in descendantsOriginal) |
... | ... | |
446 | 560 |
currentId = TagStartPositions.Count - 1; |
447 | 561 |
toEditNode.Attributes.Add(TAG_ID_ATTRIBUTE_NAME, currentId.ToString()); |
448 | 562 |
|
563 |
// Cross-referencing of the original document to the edited document |
|
449 | 564 |
TagClosingPositions.Add(originalNode.InnerStartIndex + originalNode.InnerLength); |
450 | 565 |
TagClosingLengths.Add((originalNode.OuterStartIndex + originalNode.OuterLength) - (originalNode.InnerStartIndex + originalNode.InnerLength)); |
451 | 566 |
} |
... | ... | |
476 | 591 |
* Partial HTML Preprocessing ---------------------------------------------------------------------------- |
477 | 592 |
*/ |
478 | 593 |
|
594 |
/// <summary> |
|
595 |
/// Incrementally modifies the html to render and cached info by adding a new tag |
|
596 |
/// </summary> |
|
597 |
/// <param name="htmlToEdit"></param> |
|
598 |
/// <param name="htmlOriginal"></param> |
|
599 |
/// <param name="tagToAdd"></param> |
|
600 |
/// <param name="tags"></param> |
|
601 |
/// <param name="cachedInfo"></param> |
|
602 |
/// <returns></returns> |
|
479 | 603 |
public (string, CachedInfo) PartialPreprocessHTMLAddTag(string htmlToEdit, string htmlOriginal, AnnotationTagGeneric tagToAdd, List<AnnotationTagGeneric> tags, CachedInfo cachedInfo) |
480 | 604 |
{ |
481 | 605 |
UnpackCachedInfo(cachedInfo); |
... | ... | |
547 | 671 |
}); |
548 | 672 |
} |
549 | 673 |
|
550 |
|
|
674 |
/// <summary> |
|
675 |
/// Removing tag effectively just cleans up the attributes and CSS thus has no effect |
|
676 |
/// </summary> |
|
677 |
/// <param name="htmlToEdit"></param> |
|
678 |
/// <param name="htmlOriginal"></param> |
|
679 |
/// <param name="tagToRemove"></param> |
|
680 |
/// <param name="tags"></param> |
|
681 |
/// <param name="cachedInfo"></param> |
|
682 |
/// <returns></returns> |
|
551 | 683 |
public (string, CachedInfo) PartialPreprocessHTMLRemoveTag(string htmlToEdit, string htmlOriginal, AnnotationTagGeneric tagToRemove, List<AnnotationTagGeneric> tags, CachedInfo cachedInfo) |
552 | 684 |
{ |
553 | 685 |
UnpackCachedInfo(cachedInfo); |
Backend/Core/Services/HTMLService/IHTMLService.cs | ||
---|---|---|
10 | 10 |
{ |
11 | 11 |
public interface IHTMLService |
12 | 12 |
{ |
13 |
/// <summary> |
|
14 |
/// Make a full preprocessing of an HTML document and incorporate any existing tags into it |
|
15 |
/// </summary> |
|
16 |
/// <param name="htmlSource"></param> |
|
17 |
/// <param name="tags"></param> |
|
18 |
/// <returns>tuple of (HTML document to render, info to cache in the database)</returns> |
|
13 | 19 |
public (string, CachedInfo) FullPreprocessHTML(string htmlSource, List<AnnotationTagGeneric> tags); |
20 |
/// <summary> |
|
21 |
/// Make a partial preprocessing of an HTML document by adding a new tag into it |
|
22 |
/// </summary> |
|
23 |
/// <param name="htmlToEdit">already preprocessed HTML document</param> |
|
24 |
/// <param name="htmlOriginal">original HTML document</param> |
|
25 |
/// <param name="tagToAdd">the tag to add</param> |
|
26 |
/// <param name="tags">list of all tags related to the annotation</param> |
|
27 |
/// <param name="cachedInfo">database-cached info</param> |
|
28 |
/// <returns></returns> |
|
14 | 29 |
public (string, CachedInfo) PartialPreprocessHTMLAddTag(string htmlToEdit, string htmlOriginal, AnnotationTagGeneric tagToAdd, List<AnnotationTagGeneric> tags, CachedInfo cachedInfo); |
30 |
/// <summary> |
|
31 |
/// Make a partial preprocessing of an HTML document by remove an existing tag from it |
|
32 |
/// </summary> |
|
33 |
/// <param name="htmlToEdit">already preprocessed HTML document</param> |
|
34 |
/// <param name="htmlOriginal">original HTML document</param> |
|
35 |
/// <param name="tagToRemove">the tag to remove</param> |
|
36 |
/// <param name="tags">list of all tags related to the annotation</param> |
|
37 |
/// <param name="cachedInfo">database-cached info</param> |
|
38 |
/// <returns></returns> |
|
15 | 39 |
public (string, CachedInfo) PartialPreprocessHTMLRemoveTag(string htmlToEdit, string htmlOriginal, AnnotationTagGeneric tagToRemove, List<AnnotationTagGeneric> tags, CachedInfo cachedInfo); |
16 | 40 |
} |
17 | 41 |
} |
Backend/Core/Services/Registration.cs | ||
---|---|---|
7 | 7 |
|
8 | 8 |
namespace Core.Services |
9 | 9 |
{ |
10 |
/// <summary> |
|
11 |
/// Add new services here |
|
12 |
/// </summary> |
|
10 | 13 |
public class Registration |
11 | 14 |
{ |
15 |
/// <summary> |
|
16 |
/// Registers services |
|
17 |
/// </summary> |
|
18 |
/// <param name="builder"></param> |
|
12 | 19 |
public static void RegisterServices(WebApplicationBuilder builder) |
13 | 20 |
{ |
14 | 21 |
builder.Services.AddScoped<IUserService, UserServiceEF>(); |
Backend/Core/Services/TagService/ITagService.cs | ||
---|---|---|
12 | 12 |
{ |
13 | 13 |
public interface ITagService |
14 | 14 |
{ |
15 |
/// <summary> |
|
16 |
/// Returns a tree-like structure with tag categories, tags, and subtags |
|
17 |
/// </summary> |
|
18 |
/// <param name="userRole">Role is used to discriminate categories available to admins only</param> |
|
19 |
/// <returns></returns> |
|
15 | 20 |
public TagTreeResponse GetTagTree(ERole userRole); |
21 |
/// <summary> |
|
22 |
/// Creates a new category |
|
23 |
/// </summary> |
|
24 |
/// <param name="request"></param> |
|
16 | 25 |
public void CreateCategory(CreateCategoryRequest request); |
26 |
/// <summary> |
|
27 |
/// Deleted a category by Id |
|
28 |
/// </summary> |
|
29 |
/// <param name="categoryId"></param> |
|
17 | 30 |
public void DeleteCategory(Guid categoryId); |
31 |
/// <summary> |
|
32 |
/// Updates a category by Id |
|
33 |
/// </summary> |
|
34 |
/// <param name="request"></param> |
|
35 |
/// <param name="categoryId"></param> |
|
18 | 36 |
public void UpdateCategory(ModifyCategoryRequest request, Guid categoryId); |
37 |
/// <summary> |
|
38 |
/// Creates a new tag |
|
39 |
/// </summary> |
|
40 |
/// <param name="request"></param> |
|
19 | 41 |
public void CreateTag(CreateTagRequest request); |
42 |
/// <summary> |
|
43 |
/// Delete tag by Id |
|
44 |
/// </summary> |
|
45 |
/// <param name="tagId"></param> |
|
20 | 46 |
public void DeleteTag(Guid tagId); |
47 |
/// <summary> |
|
48 |
/// Update tag by Id |
|
49 |
/// </summary> |
|
50 |
/// <param name="request"></param> |
|
51 |
/// <param name="tagId"></param> |
|
21 | 52 |
public void UpdateTag(ModifyTagRequest request, Guid tagId); |
53 |
/// <summary> |
|
54 |
/// Create a subtag |
|
55 |
/// </summary> |
|
56 |
/// <param name="request"></param> |
|
22 | 57 |
public void CreateSubTag(CreateSubTagRequest request); |
58 |
/// <summary> |
|
59 |
/// Delete subtag by Id |
|
60 |
/// </summary> |
|
61 |
/// <param name="subtagId"></param> |
|
23 | 62 |
public void DeleteSubTag(Guid subtagId); |
63 |
/// <summary> |
|
64 |
/// Update subtag by Id |
|
65 |
/// </summary> |
|
66 |
/// <param name="request"></param> |
|
67 |
/// <param name="subtagId"></param> |
|
24 | 68 |
public void UpdateSubTag(ModifySubTagRequest request, Guid subtagId); |
69 |
/// <summary> |
|
70 |
/// Adds a note to tag's instance |
|
71 |
/// </summary> |
|
72 |
/// <param name="annotationId">Annotation</param> |
|
73 |
/// <param name="occurrenceId">Id of the Tag</param> |
|
74 |
/// <param name="user">User that's doing the adding</param> |
|
75 |
/// <param name="request"></param> |
|
76 |
/// <param name="isFinal">Whether the annotationId is for a FinalAnnotation or Annotation</param> |
|
25 | 77 |
public void AddNoteToTagInstance(Guid annotationId, Guid occurrenceId, User user, AddNoteToTagOccurenceRequest request, bool isFinal); |
26 | 78 |
} |
27 | 79 |
} |
Backend/Core/Services/TagService/TagServiceEF.cs | ||
---|---|---|
274 | 274 |
|
275 | 275 |
public void AddNoteToTagInstance(Guid annotationId, Guid occurrenceId, User user, AddNoteToTagOccurenceRequest request, bool isFinal) |
276 | 276 |
{ |
277 |
// We need to differentiate whether or not the annotation is final |
|
277 | 278 |
Annotation annotation = null; |
278 | 279 |
try |
279 | 280 |
{ |
Backend/Core/Services/UserService/IUserService.cs | ||
---|---|---|
11 | 11 |
{ |
12 | 12 |
public interface IUserService |
13 | 13 |
{ |
14 |
/// <summary> |
|
15 |
/// Creates a new user |
|
16 |
/// </summary> |
|
17 |
/// <param name="username"></param> |
|
18 |
/// <param name="name"></param> |
|
19 |
/// <param name="surname"></param> |
|
20 |
/// <param name="password"></param> |
|
21 |
/// <param name="role"></param> |
|
22 |
/// <returns></returns> |
|
14 | 23 |
public User? CreateUser(string username, string name, string surname, string password, ERole role); |
24 |
/// <summary> |
|
25 |
/// Returns a user with the specified username or null if no such user exists |
|
26 |
/// </summary> |
|
27 |
/// <param name="username"></param> |
|
28 |
/// <returns></returns> |
|
15 | 29 |
public User? GetUserByUsername(string username); |
30 |
/// <summary> |
|
31 |
/// Returns a user with the specified Id or null if no such user exists |
|
32 |
/// </summary> |
|
33 |
/// <param name="id"></param> |
|
34 |
/// <returns></returns> |
|
16 | 35 |
public User? GetUserById(Guid id); |
36 |
/// <summary> |
|
37 |
/// Updates information about the user |
|
38 |
/// Pass null as a parameter if you dont want to update it |
|
39 |
/// </summary> |
|
40 |
/// <param name="user"></param> |
|
41 |
/// <param name="username"></param> |
|
42 |
/// <param name="name"></param> |
|
43 |
/// <param name="surname"></param> |
|
44 |
/// <param name="role"></param> |
|
45 |
/// <returns></returns> |
|
17 | 46 |
public User UpdateUser(User user, string? username = null, string? name = null, string? surname = null, ERole? role = null); |
47 |
/// <summary> |
|
48 |
/// Updates information about the user |
|
49 |
/// Pass null as a parameter if you dont want to update it |
|
50 |
/// </summary> |
|
51 |
/// <param name="user"></param> |
|
52 |
/// <param name="username"></param> |
|
53 |
/// <param name="name"></param> |
|
54 |
/// <param name="surname"></param> |
|
55 |
/// <param name="role"></param> |
|
56 |
/// <returns></returns> |
|
18 | 57 |
public User? UpdateUser(Guid userId, string? username = null, string? name = null, string? surname = null, ERole? role = null); |
58 |
/// <summary> |
|
59 |
/// Sets a new password |
|
60 |
/// </summary> |
|
61 |
/// <param name="user"></param> |
|
62 |
/// <param name="newPassword"></param> |
|
63 |
/// <returns></returns> |
|
19 | 64 |
public User ChangePassword(User user, string newPassword); |
65 |
/// <summary> |
|
66 |
/// Sets a new password |
|
67 |
/// </summary> |
|
68 |
/// <param name="user"></param> |
|
69 |
/// <param name="newPassword"></param> |
|
70 |
/// <returns></returns> |
|
20 | 71 |
public User? ChangePassword(Guid userId, string newPassword); |
72 |
/// <summary> |
|
73 |
/// Check if the user with this username has this password |
|
74 |
/// </summary> |
|
75 |
/// <param name="username"></param> |
|
76 |
/// <param name="password"></param> |
|
77 |
/// <returns></returns> |
|
21 | 78 |
public User? CheckUsernamePassword(string username, string password); |
79 |
/// <summary> |
|
80 |
/// Returns list of all users |
|
81 |
/// </summary> |
|
82 |
/// <returns></returns> |
|
22 | 83 |
public UserList GetUsers(); |
84 |
/// <summary> |
|
85 |
/// Deletes a user |
|
86 |
/// </summary> |
|
87 |
/// <param name="userId"></param> |
|
23 | 88 |
public void DeleteUser(Guid userId); |
24 | 89 |
} |
25 | 90 |
} |
Backend/Core/Services/UserService/UserServiceEF.cs | ||
---|---|---|
16 | 16 |
{ |
17 | 17 |
public class UserServiceEF : IUserService |
18 | 18 |
{ |
19 |
// DI |
|
20 |
|
|
19 | 21 |
private readonly DatabaseContext _databaseContext; |
20 | 22 |
private readonly ILogger _logger; |
21 | 23 |
private readonly IMapper _mapper; |
Backend/Core/ZipUtils/Export.cs | ||
---|---|---|
10 | 10 |
|
11 | 11 |
namespace Core.ZipUtils |
12 | 12 |
{ |
13 |
/// <summary> |
|
14 |
/// Static methods for database exporting |
|
15 |
/// </summary> |
|
13 | 16 |
public class Export |
14 | 17 |
{ |
18 |
/// <summary> |
|
19 |
/// Exports the specified annotations |
|
20 |
/// </summary> |
|
21 |
/// <param name="documents">list of documents to export</param> |
|
22 |
/// <param name="documentAnnotations">document-annotations to export mapping</param> |
|
23 |
/// <param name="documentFinalAnnotations">document-final annotations to export mapping</param> |
|
24 |
/// <param name="annotationTags">annotation-annotation tags mapping</param> |
|
25 |
/// <param name="finalAnnotationTags">final annotation-final annotation tags mapping</param> |
|
26 |
/// <returns></returns> |
|
15 | 27 |
public static MemoryStream FullExport(List<Document> documents, Dictionary<Document, List<Annotation>> documentAnnotations, Dictionary<Document, FinalAnnotation> documentFinalAnnotations, |
16 | 28 |
Dictionary<Annotation, List<AnnotationTag>> annotationTags, Dictionary<FinalAnnotation, List<FinalAnnotationTag>> finalAnnotationTags) |
17 | 29 |
{ |
18 | 30 |
MemoryStream ms = new MemoryStream(); |
31 |
// Set keepOpen to true so that Dispose() does not close the MemoryStream |
|
19 | 32 |
var archive = new ZipArchive(ms, ZipArchiveMode.Create, true); |
20 | 33 |
|
21 | 34 |
for (int docIndex = 0; docIndex < documents.Count; docIndex++) |
... | ... | |
37 | 50 |
CreateFile(documentDir + $"/annotation_{annotationIndex:00000}.json", annotationInfoJson, archive); |
38 | 51 |
} |
39 | 52 |
|
53 |
// Deal with final annotation if it exists |
|
40 | 54 |
var finalAnnotation = documentFinalAnnotations[document]; |
41 | 55 |
if (finalAnnotation == null) |
42 | 56 |
{ |
... | ... | |
48 | 62 |
CreateFile(documentDir + "/final.json", finalAnnotationInfoJson, archive); |
49 | 63 |
} |
50 | 64 |
|
65 |
// Dispose of archive to close the header |
|
51 | 66 |
archive.Dispose(); |
52 | 67 |
ms.Position = 0; |
53 | 68 |
return ms; |
54 | 69 |
} |
55 | 70 |
|
71 |
/// <summary> |
|
72 |
/// Creates a file and writes to it |
|
73 |
/// </summary> |
|
74 |
/// <param name="path">path to file</param> |
|
75 |
/// <param name="fileContent">string to write</param> |
|
76 |
/// <param name="archive">archive to write it to</param> |
|
56 | 77 |
private static void CreateFile(string path, string fileContent, ZipArchive archive) |
57 | 78 |
{ |
58 | 79 |
var entry = archive.CreateEntry(path); |
... | ... | |
61 | 82 |
entryStream.Close(); |
62 | 83 |
} |
63 | 84 |
|
85 |
/// <summary> |
|
86 |
/// Dumps a Document into JSON-serialized ExportDocumentInfo |
|
87 |
/// </summary> |
|
88 |
/// <param name="document">Document to serialize</param> |
|
89 |
/// <returns>JSON-serialized ExportDocumentInfo</returns> |
|
64 | 90 |
private static string DumpDocument(Document document) |
65 | 91 |
{ |
66 | 92 |
ExportDocumentInfo documentInfo = new(); |
... | ... | |
71 | 97 |
return JsonConvert.SerializeObject(documentInfo); |
72 | 98 |
} |
73 | 99 |
|
100 |
/// <summary> |
|
101 |
/// Dumps annotation into JSON-serialized ExportAnnotationInfo |
|
102 |
/// </summary> |
|
103 |
/// <param name="annotation">Annotation to dump</param> |
|
104 |
/// <param name="tags">Tags related to the annotation</param> |
|
105 |
/// <param name="documentId">Id of the document the annotation is related to</param> |
|
106 |
/// <returns>JSON-serialized ExportAnnotationInfo</returns> |
|
74 | 107 |
private static string DumpAnnotation(Annotation annotation, List<AnnotationTagGeneric> tags, Guid documentId) |
75 | 108 |
{ |
76 | 109 |
ExportAnnotationInfo annotationInfo = new(); |
... | ... | |
108 | 141 |
|
109 | 142 |
public class ExportDocumentInfo |
110 | 143 |
{ |
144 |
/// <summary> |
|
145 |
/// Document name |
|
146 |
/// </summary> |
|
111 | 147 |
public string Name { get; set; } |
148 |
/// <summary> |
|
149 |
/// Original document content |
|
150 |
/// </summary> |
|
112 | 151 |
public string Content { get; set; } |
152 |
/// <summary> |
|
153 |
/// Id of the document |
|
154 |
/// </summary> |
|
113 | 155 |
public Guid DocumentId { get; set; } |
114 | 156 |
} |
115 | 157 |
|
116 | 158 |
public class ExportAnnotationInfo |
117 | 159 |
{ |
160 |
/// <summary> |
Také k dispozici: Unified diff
Added comments to backend