commit 15c88dc131a52f922163a64f43ba63b6df65945c
Author: Vojtěch Bartička <aitakaitov@gmail.com>
Date:   Fri Apr 29 16:00:12 2022 +0200

    Added sentiment to Tags and SubTags, modified create/update tag/subtag endpoints, added set instance sentiment endpoint

diff --git a/Backend/Backend/Controllers/AnnotationController.cs b/Backend/Backend/Controllers/AnnotationController.cs
index d45af4f..203a863 100644
--- a/Backend/Backend/Controllers/AnnotationController.cs
+++ b/Backend/Backend/Controllers/AnnotationController.cs
@@ -196,5 +196,31 @@ namespace RestAPI.Controllers
 
         }
 
+        [HttpPut("/annotation/{annotationId}/{instanceId}/sentiment")]
+        [ProducesResponseType((int)HttpStatusCode.OK)]
+        [ProducesResponseType((int)HttpStatusCode.Forbidden)]
+        public ActionResult SetTagInstanceSentiment([FromServices] ClientInfo clientInfo, Guid annotationId, Guid instanceId, SetInstanceSentimentRequest request)
+        {
+            if (clientInfo.LoggedUser == null)
+            {
+                logger.Warning("ClientInfo has null LoggerUser in [Authorized] controller /annotations");
+                return Problem();
+            }
+
+            try
+            {
+                annotationService.SetTagInstanceSentiment(annotationId, instanceId, clientInfo.LoggedUser.Id, clientInfo.LoggedUser.Role, request.Sentiment);
+                return Ok();
+            }
+            catch (InvalidOperationException e)
+            {
+                throw new BadRequestException(e.Message);
+            }
+            catch (UnauthorizedAccessException)
+            {
+                return Forbid();
+            }
+
+        }
     }
 }
diff --git a/Backend/Core/Entities/AnnotationTag.cs b/Backend/Core/Entities/AnnotationTag.cs
index 798b090..8fbb2ec 100644
--- a/Backend/Core/Entities/AnnotationTag.cs
+++ b/Backend/Core/Entities/AnnotationTag.cs
@@ -1,4 +1,5 @@
-﻿using System;
+﻿using Models.Enums;
+using System;
 using System.Collections.Generic;
 using System.ComponentModel.DataAnnotations;
 using System.ComponentModel.DataAnnotations.Schema;
@@ -21,5 +22,6 @@ namespace Core.Entities
         public string Note { get; set; }
         public int Position { get; set; }
         public int Length { get; set; }
+        public ETagSentiment? Sentiment { get; set; }
     }
 }
diff --git a/Backend/Core/Entities/SubTag.cs b/Backend/Core/Entities/SubTag.cs
index 3385346..15f7df8 100644
--- a/Backend/Core/Entities/SubTag.cs
+++ b/Backend/Core/Entities/SubTag.cs
@@ -11,7 +11,7 @@ namespace Core.Entities
     {
         public string Name { get; set; }
         public string Description { get; set; }
-        
         public Tag Tag { get; set; }
+        public bool SentimentEnabled { get; set; } = false;
     }
 }
diff --git a/Backend/Core/Entities/Tag.cs b/Backend/Core/Entities/Tag.cs
index 3c6fa3d..a2c2ea5 100644
--- a/Backend/Core/Entities/Tag.cs
+++ b/Backend/Core/Entities/Tag.cs
@@ -14,5 +14,6 @@ namespace Core.Entities
         public string Name { get; set; }
         public string Description { get; set; }
         public string Color { get; set; }
+        public bool SentimentEnabled { get; set; } = false;
     }
 }
diff --git a/Backend/Core/Seeding/DummyTags.cs b/Backend/Core/Seeding/DummyTags.cs
index 43f73f2..f56aad6 100644
--- a/Backend/Core/Seeding/DummyTags.cs
+++ b/Backend/Core/Seeding/DummyTags.cs
@@ -33,7 +33,8 @@ namespace Core.Seeding
                 Name = "pristup_zadost",
                 Description = "Informování subjektu o jeho právu na přístup k osobním údajům vztahujícím se k jeho osobě na jeho žádost.",
                 Color = "#FF0000",
-                Category = rightsCat        
+                Category = rightsCat,
+                SentimentEnabled = true
             };
             context.Tags.Add(pristupZadostTag);
 
diff --git a/Backend/Core/Services/AnnotationService/AnnotationServiceEF.cs b/Backend/Core/Services/AnnotationService/AnnotationServiceEF.cs
index 6886c4f..f59a3f9 100644
--- a/Backend/Core/Services/AnnotationService/AnnotationServiceEF.cs
+++ b/Backend/Core/Services/AnnotationService/AnnotationServiceEF.cs
@@ -562,12 +562,22 @@ namespace Core.Services.AnnotationService
             {
                 annotationTag.Tag = context.Tags.Where(t => t.Id == request.Id).Single();
                 annotationTag.SubTag = null;
+
+                if (annotationTag.Tag.SentimentEnabled)
+                {
+                    annotationTag.Sentiment = ETagSentiment.NEUTRAL;
+                }
             }
             else if (request.Type == ETagType.SUBTAG)
             {
                 var subTag = context.SubTags.Where(st => st.Id == request.Id).Include(st => st.Tag).Single();
                 annotationTag.SubTag = subTag;
                 annotationTag.Tag = subTag.Tag;
+
+                if (annotationTag.SubTag.SentimentEnabled)
+                {
+                    annotationTag.Sentiment = ETagSentiment.NEUTRAL;
+                }
             }
             else
             {
@@ -615,5 +625,46 @@ namespace Core.Services.AnnotationService
 
             context.SaveChanges();
         }
+
+        public void SetTagInstanceSentiment(Guid annotationId, Guid instanceId, Guid userId, ERole userRole, ETagSentiment sentiment)
+        {
+            Annotation annotation = null;
+            try
+            {
+                annotation = context.Annotations
+                   .Where(a => a.Id == annotationId)
+                   .Include(a => a.User)
+                   .Include(a => a.Document).ThenInclude(d => d.Content)
+                   .First();
+
+            }
+            catch (Exception ex)
+            {
+                throw new InvalidOperationException("Could not find annotation");
+            }
+
+
+            if (userRole < ERole.ADMINISTRATOR)
+            {
+                if (annotation.User.Id != userId)
+                {
+                    throw new UnauthorizedAccessException($"User {userId} does not have assigned annotation {annotationId}");
+                }
+            }
+
+
+            var tagInstances = context.AnnotationTags.Where(at => at.Instance == instanceId).ToList();
+            if (tagInstances.Count() == 0)
+            {
+                throw new InvalidOperationException("No such instance found");
+            }
+
+            foreach (var tagInstance in tagInstances)
+            {
+                tagInstance.Sentiment = sentiment;
+            }
+
+            context.SaveChanges();
+        }
     }
 }
diff --git a/Backend/Core/Services/AnnotationService/IAnnotationService.cs b/Backend/Core/Services/AnnotationService/IAnnotationService.cs
index 6a225d5..0d6a8d5 100644
--- a/Backend/Core/Services/AnnotationService/IAnnotationService.cs
+++ b/Backend/Core/Services/AnnotationService/IAnnotationService.cs
@@ -16,5 +16,8 @@ namespace Core.Services.AnnotationService
         public void AddAnnotationInstance(Guid annotationId, Guid userId, ERole userRole, AnnotationInstanceAddRequest request);
         public void DeleteAnnotationInstance(Guid annotationId, Guid tagInstanceId, Guid loggedUserId, ERole userRole);
         public void AddNoteToAnnotation(Guid annotationId, Guid userId, ERole userRole, AddNoteToAnnotationRequest request);
+        public void SetTagInstanceSentiment(Guid annotationId, Guid instanceId, Guid userId, ERole userRole, ETagSentiment sentiment);
+
+
     }
 }
diff --git a/Backend/Core/Services/TagService/TagServiceEF.cs b/Backend/Core/Services/TagService/TagServiceEF.cs
index 0ea6afe..25b00eb 100644
--- a/Backend/Core/Services/TagService/TagServiceEF.cs
+++ b/Backend/Core/Services/TagService/TagServiceEF.cs
@@ -129,7 +129,7 @@ namespace Core.Services.TagService
 
             if (request.DisabledForAnnotators != null)
             {
-                category.DisabledForAnnotators = (bool) request.DisabledForAnnotators;
+                category.DisabledForAnnotators = (bool)request.DisabledForAnnotators;
             }
 
             databaseContext.SaveChanges();
@@ -149,11 +149,13 @@ namespace Core.Services.TagService
             var category = databaseContext.TagCategories.First(tc => tc.Id == request.CategoryId);
 
             databaseContext.Tags.Add(new Entities.Tag()
+            databaseContext.Tags.Add(new Tag()
             {
                 Name = request.Name,
                 Color = request.Color,
                 Description = request.Description,
-                Category = category
+                Category = category,
+                SentimentEnabled = request.SentimentEnabled
             });
 
             databaseContext.SaveChanges();
@@ -192,6 +194,11 @@ namespace Core.Services.TagService
                 tag.Description = request.Description;
             }
 
+            if (request.SentimentEnabled != null)
+            {
+                tag.SentimentEnabled = (bool)request.SentimentEnabled;
+            }
+
             databaseContext.SaveChanges();
         }
 
@@ -211,7 +218,8 @@ namespace Core.Services.TagService
             {
                 Name = request.Name,
                 Description = request.Description,
-                Tag = tag
+                Tag = tag,
+                SentimentEnabled = request.SentimentEnabled
             });
 
             databaseContext.SaveChanges();
@@ -241,6 +249,11 @@ namespace Core.Services.TagService
                 subtag.Description = request.Description;
             }
 
+            if (request.SentimentEnabled != null)
+            {
+                subtag.SentimentEnabled = (bool) request.SentimentEnabled;
+            }
+
             databaseContext.SaveChanges();
         }
 
diff --git a/Backend/Models/Enums/ETagSentiment.cs b/Backend/Models/Enums/ETagSentiment.cs
new file mode 100644
index 0000000..1c6bac0
--- /dev/null
+++ b/Backend/Models/Enums/ETagSentiment.cs
@@ -0,0 +1,15 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Models.Enums
+{
+    public enum ETagSentiment
+    {
+        NEUTRAL, 
+        POSITIVE,
+        NEGATIVE
+    }
+}
diff --git a/Backend/Models/Tags/CreateSubTagRequest.cs b/Backend/Models/Tags/CreateSubTagRequest.cs
index 9957d39..90c3ddf 100644
--- a/Backend/Models/Tags/CreateSubTagRequest.cs
+++ b/Backend/Models/Tags/CreateSubTagRequest.cs
@@ -9,7 +9,8 @@ namespace Models.Tags
     public class CreateSubTagRequest
     {
         public string Name { get; set; }
-        public string Description { get; set; }
+        public string Description { get; set; } = "";
         public Guid TagId { get; set; }
+        public bool SentimentEnabled { get; set; } = false;
     }
 }
diff --git a/Backend/Models/Tags/CreateTagRequest.cs b/Backend/Models/Tags/CreateTagRequest.cs
index fc161d8..6f38497 100644
--- a/Backend/Models/Tags/CreateTagRequest.cs
+++ b/Backend/Models/Tags/CreateTagRequest.cs
@@ -12,5 +12,6 @@ namespace Models.Tags
         public string Name { get; set; }
         public string Description { get; set; } = "";
         public string Color { get; set; }
+        public bool SentimentEnabled { get; set; } = false;
     }
 }
diff --git a/Backend/Models/Tags/ModifySubTagRequest.cs b/Backend/Models/Tags/ModifySubTagRequest.cs
index 1b1dabe..055f34f 100644
--- a/Backend/Models/Tags/ModifySubTagRequest.cs
+++ b/Backend/Models/Tags/ModifySubTagRequest.cs
@@ -10,5 +10,6 @@ namespace Models.Tags
     {
         public string? Name { get; set; }
         public string? Description { get; set; }
+        public bool? SentimentEnabled { get; set; }
     }
 }
diff --git a/Backend/Models/Tags/ModifyTagRequest.cs b/Backend/Models/Tags/ModifyTagRequest.cs
index df67e34..2bcb840 100644
--- a/Backend/Models/Tags/ModifyTagRequest.cs
+++ b/Backend/Models/Tags/ModifyTagRequest.cs
@@ -11,5 +11,6 @@ namespace Models.Tags
         public string? Name { get; set; }
         public string? Description { get; set; }
         public string? Color { get; set; }
+        public bool? SentimentEnabled { get; set; }
     }
 }
diff --git a/Backend/Models/Tags/SetInstanceSentimentRequest.cs b/Backend/Models/Tags/SetInstanceSentimentRequest.cs
new file mode 100644
index 0000000..fa9fcb0
--- /dev/null
+++ b/Backend/Models/Tags/SetInstanceSentimentRequest.cs
@@ -0,0 +1,14 @@
+﻿using Models.Enums;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Models.Tags
+{
+    public class SetInstanceSentimentRequest
+    {
+        public ETagSentiment Sentiment { get; set; }
+    }
+}
