Projekt

Obecné

Profil

Stáhnout (29.2 KB) Statistiky
| Větev: | Tag: | Revize:
1
using Core.Contexts;
2
using Core.Entities;
3
using Models.Annotations;
4
using Models.Enums;
5
using Serilog;
6
using System;
7
using System.Collections.Generic;
8
using System.Linq;
9
using System.Text;
10
using System.Threading.Tasks;
11
using Microsoft.EntityFrameworkCore;
12
using AutoMapper;
13
using Models.Tags;
14
using Ganss.XSS;
15
using HtmlAgilityPack;
16
using System.Text.RegularExpressions;
17
using Newtonsoft.Json;
18
using Core.GraphUtils;
19

    
20
namespace Core.Services.AnnotationService
21
{
22
    public class AnnotationServiceEF : IAnnotationService
23
    {
24
        private readonly DatabaseContext context;
25
        private readonly ILogger logger;
26
        private readonly IMapper mapper;
27
        private readonly IHTMLService htmlService;
28

    
29

    
30
        public AnnotationServiceEF(DatabaseContext context, ILogger logger, IMapper mapper, IHTMLService htmlService)
31
        {
32
            this.context = context;
33
            this.logger = logger;
34
            this.mapper = mapper;
35
            this.htmlService = htmlService;
36
        }
37

    
38
        public void CreateDocumentAnnotations(AnnotationsAddRequest request, Guid clientUserId)
39
        {
40
            User addingUser = context.Users.Single(u => u.Id == clientUserId);
41

    
42
            // Check the documents exist
43
            var documents = context.Documents.Where(d => request.DocumentIdList.Contains(d.Id)).ToList();
44
            if (documents.Count() != request.DocumentIdList.Count)
45
            {
46
                logger.Information($"Received a non-existent Document ID when assigning documents to users");
47
                throw new InvalidOperationException($"{request.DocumentIdList.Count - documents.Count()} of the received documents do not exist");
48
            }
49

    
50
            var users = context.Users.Where(u => request.UserIdList.Contains(u.Id)).ToList();
51
            foreach (var user in users)
52
            {
53
                var userAnnotatedDocuments = context.Annotations
54
                    .Where(a => !(a is FinalAnnotation))
55
                    .Where(a => a.User == user)
56
                    .Select(a => a.Document)
57
                    .ToList();
58
                foreach (var doc in documents)
59
                {
60
                    if (userAnnotatedDocuments.Contains(doc))
61
                    {
62
                        logger.Information($"User {user.Username} has already been assigned the document {doc.Id}, ignoring");
63
                        continue;
64
                    }
65

    
66
                    context.Annotations.Add(new Annotation()
67
                    {
68
                        User = user,
69
                        UserAssigned = addingUser,
70
                        DateAssigned = DateTime.Now,
71
                        DateLastChanged = DateTime.Now,
72
                        Document = doc,
73
                        State = EState.NEW,
74
                        Note = ""
75
                    });
76
                }
77
            }
78

    
79
            context.SaveChanges();
80
        }
81

    
82
        public AnnotationListResponse GetUserAnnotations(Guid userId)
83
        {
84
            var annotations = context.Annotations
85
                .Where(a => !(a is FinalAnnotation))
86
                .Where(a => a.User.Id == userId)
87
                .Include(a => a.Document)
88
                .ToList();
89

    
90
            var infos = new List<AnnotationListInfo>();
91
            foreach (var annotation in annotations)
92
            {
93
                infos.Add(new AnnotationListInfo()
94
                {
95
                    AnnotationId = annotation.Id,
96
                    DocumentName = annotation.Document.Name,
97
                    State = annotation.State
98
                });
99
            }
100

    
101
            return new AnnotationListResponse()
102
            {
103
                Annotations = infos
104
            };
105
        }
106

    
107
        public void AddNoteToAnnotation(Guid annotationId, Guid userId, ERole userRole, AddNoteToAnnotationRequest request, bool isFinal)
108
        {
109
            Annotation annotation = null;
110
            try
111
            {
112
                if (!isFinal)
113
                {
114
                    annotation = context.Annotations.Include(a => a.User).First(a => a.Id == annotationId);
115
                }
116
                else
117
                {
118
                    annotation = context.FinalAnnotations.Include(a => a.User).First(a => a.Id == annotationId);
119
                }
120
            }
121
            catch (Exception)
122
            {
123
                throw new InvalidOperationException("Annotation not found");
124
            }
125

    
126
            if (userRole < ERole.ADMINISTRATOR && annotation.User.Id != userId)
127
            {
128
                throw new UnauthorizedAccessException("User does not have access to this annotation");
129
            }
130

    
131
            annotation.Note = request.Note;
132
            context.SaveChanges();
133
        }
134

    
135

    
136
        public AnnotationInfo GetAnnotation(Guid annotationId, Guid userId, ERole userRole, bool isFinal)
137
        {
138
            Annotation annotation = new();
139
            if (!isFinal)
140
            {
141
                annotation = context.Annotations
142
                .Where(a => !(a is FinalAnnotation))
143
                .Where(a => a.Id == annotationId)
144
                .Include(a => a.User)
145
                .Include(a => a.Document).ThenInclude(d => d.Content)
146
                .First();
147
            }
148
            else
149
            {
150
                annotation = context.FinalAnnotations
151
                .Where(a => a.Id == annotationId)
152
                .Include(a => a.User)
153
                .Include(a => a.Document).ThenInclude(d => d.Content)
154
                .First();
155
            }
156

    
157

    
158
            if (userRole < ERole.ADMINISTRATOR)
159
            {
160
                if (annotation.User.Id != userId)
161
                {
162
                    throw new UnauthorizedAccessException($"User {userId} does not have assigned annotation {annotationId}");
163
                }
164
            }
165

    
166
            var documentContent = context.Documents.Where(d => d.Id == annotation.Document.Id).Select(d => d.Content).First();
167

    
168
            IQueryable<AnnotationTagGeneric> tagsQuery;
169
            List<AnnotationTagGeneric> tags;
170
            if (!isFinal)
171
            {
172
                tagsQuery = context.AnnotationTags.Where(at => at.Annotation.Id == annotationId);
173
            }
174
            else
175
            {
176
                tagsQuery = context.FinalAnnotationTags.Where(at => at.Annotation.Id == annotationId);
177
            }
178

    
179
            tags = tagsQuery.Include(at => at.Tag)
180
                .ThenInclude(t => t.Category)
181
                .Include(at => at.SubTag)
182
                .OrderBy(at => at.Position)
183
                .Select(at => at)
184
                .ToList();
185

    
186
            List<TagInstanceInfo> tagInstanceInfos = new();
187
            foreach (var tag in tags)
188
            {
189
                var tagInstance = mapper.Map<TagInstanceInfo>(tag);
190
                tagInstanceInfos.Add(tagInstance);
191
            }
192

    
193
            var docToRender = "";
194
            HTMLService.CachedInfo cachedInfoToReturn = new();
195
            if (annotation.CachedDocumentHTML == "")
196
            {
197
                var result = htmlService.FullPreprocessHTML(documentContent.Content, tags);
198
                cachedInfoToReturn = result.Item2;
199
                docToRender = result.Item1;
200

    
201
                annotation.CachedStartPositions = JsonConvert.SerializeObject(cachedInfoToReturn.TagStartPositions);
202
                annotation.CachedLengths = JsonConvert.SerializeObject(cachedInfoToReturn.TagStartLengths);
203
                annotation.CachedClosingPositions = JsonConvert.SerializeObject(cachedInfoToReturn.TagClosingPositions);
204
                annotation.CachedClosingLengths = JsonConvert.SerializeObject(cachedInfoToReturn.TagClosingLengths);
205
                annotation.CachedCSS = JsonConvert.SerializeObject(cachedInfoToReturn.TagInstanceCSS);
206
                annotation.ModifiedType = EModified.NONE;
207
                annotation.CachedDocumentHTML = docToRender;
208
                context.SaveChanges();
209
            }
210
            else
211
            {
212
                docToRender = annotation.CachedDocumentHTML;
213
                cachedInfoToReturn = new()
214
                {
215
                    TagStartPositions = JsonConvert.DeserializeObject<List<int>>(annotation.CachedStartPositions),
216
                    TagStartLengths = JsonConvert.DeserializeObject<List<int>>(annotation.CachedLengths),
217
                    TagClosingPositions = JsonConvert.DeserializeObject<List<int>>(annotation.CachedClosingPositions),
218
                    TagClosingLengths = JsonConvert.DeserializeObject<List<int>>(annotation.CachedClosingLengths),
219
                    TagInstanceCSS = JsonConvert.DeserializeObject<List<TagInstanceCSSInfo>>(annotation.CachedCSS)
220
                };
221

    
222
                // The annotation has been modified and we need to either add the new tag or remove the tag
223
                if (annotation.ModifiedType != EModified.NONE)
224
                {
225
                    if (annotation.ModifiedType == EModified.ADDED)
226
                    {
227

    
228
                        AnnotationTagGeneric lastModifiedTag = isFinal ? context.FinalAnnotationTags.Where(at => at.Id == annotation.LastModifiedTagId).First() : 
229
                            context.AnnotationTags.Where(at => at.Id == annotation.LastModifiedTagId).First();
230

    
231
                        var result = htmlService.PartialPreprocessHTMLAddTag(docToRender, documentContent.Content, lastModifiedTag, tags, cachedInfoToReturn);
232
                        docToRender = result.Item1;
233
                        cachedInfoToReturn = result.Item2;
234
                    }
235
                    else if (annotation.ModifiedType == EModified.REMOVED)
236
                    {
237
                        var result = htmlService.PartialPreprocessHTMLRemoveTag(docToRender, documentContent.Content, new AnnotationTag() { Id = annotation.LastModifiedTagId.Value }, tags, cachedInfoToReturn);
238
                        docToRender = result.Item1;
239
                        cachedInfoToReturn = result.Item2;
240
                    }
241

    
242
                    annotation.ModifiedType = EModified.NONE;
243
                    annotation.CachedStartPositions = JsonConvert.SerializeObject(cachedInfoToReturn.TagStartPositions);
244
                    annotation.CachedLengths = JsonConvert.SerializeObject(cachedInfoToReturn.TagStartLengths);
245
                    annotation.CachedClosingPositions = JsonConvert.SerializeObject(cachedInfoToReturn.TagClosingPositions);
246
                    annotation.CachedClosingLengths = JsonConvert.SerializeObject(cachedInfoToReturn.TagClosingLengths);
247
                    annotation.CachedDocumentHTML = docToRender;
248
                    annotation.CachedCSS = JsonConvert.SerializeObject(cachedInfoToReturn.TagInstanceCSS);
249
                    context.SaveChanges();
250
                }
251
            }
252

    
253
            // We probably cannot use AutoMapper since we are dealing with too many different entities
254
            AnnotationInfo annotationInfo = new()
255
            {
256
                SourceDocumentContent = documentContent.Content,
257
                DocumentToRender = docToRender,
258
                TagStartPositions = cachedInfoToReturn.TagStartPositions.ToArray(),
259
                TagLengths = cachedInfoToReturn.TagStartLengths.ToArray(),
260
                Note = annotation.Note,
261
                State = annotation.State,
262
                Type = IsHtml(documentContent.Content) ? EDocumentType.HTML : EDocumentType.TEXT,
263
                TagInstances = tagInstanceInfos,
264
                CSSInfo = cachedInfoToReturn.TagInstanceCSS
265
            };
266

    
267
            return annotationInfo;
268
        }
269

    
270
        // TODO temporary
271
        private bool IsHtml(string text)
272
        {
273
            return text.Contains("<html>");
274
        }
275

    
276
        public void AddAnnotationInstance(Guid annotationId, Guid userId, ERole userRole, AnnotationInstanceAddRequest request, bool isFinal)
277
        {
278
            Annotation annotation = new();
279
            if (!isFinal)
280
            {
281
                annotation = context.Annotations
282
                    .Where(a => !(a is FinalAnnotation))
283
                    .Where(a => a.Id == annotationId)
284
                    .Include(a => a.User)
285
                    .Include(a => a.Document).ThenInclude(d => d.Content)
286
                    .First();
287
            }
288
            else
289
            {
290
                annotation = context.FinalAnnotations
291
                    .Where(a => a.Id == annotationId)
292
                    .Include(a => a.User)
293
                    .Include(a => a.Document).ThenInclude(d => d.Content)
294
                    .First();
295
            }
296

    
297
            if (userRole < ERole.ADMINISTRATOR)
298
            {
299
                if (annotation.User.Id != userId)
300
                {
301
                    throw new UnauthorizedAccessException($"User {userId} does not have assigned annotation {annotationId}");
302
                }
303
            }
304

    
305
            if (annotation.State == EState.NEW)
306
            {
307
                annotation.State = EState.IN_PROGRESS;
308
            }
309

    
310
            AnnotationTagGeneric annotationTag = new();
311
            if (isFinal)
312
            {
313
                annotationTag = new FinalAnnotationTag()
314
                {
315
                    Id = Guid.NewGuid(),
316
                    Annotation = annotation as FinalAnnotation,
317
                    Instance = request.InstanceId == null ? Guid.NewGuid() : request.InstanceId.Value,
318
                    Length = request.Length,
319
                    Position = request.Position,
320
                    SelectedText = request.SelectedText,
321
                    Note = "",
322
                    IsFinal = true
323
                };
324
            }
325
            else
326
            {
327
                annotationTag = new AnnotationTag()
328
                {
329
                    Id = Guid.NewGuid(),
330
                    Annotation = annotation as Annotation,
331
                    Instance = request.InstanceId == null ? Guid.NewGuid() : request.InstanceId.Value,
332
                    Length = request.Length,
333
                    Position = request.Position,
334
                    SelectedText = request.SelectedText,
335
                    Note = ""
336
                };
337
            }
338

    
339
            if (request.Type == ETagType.TAG)
340
            {
341
                annotationTag.Tag = context.Tags.Where(t => t.Id == request.Id).Single();
342
                annotationTag.SubTag = null;
343

    
344
                if (annotationTag.Tag.SentimentEnabled)
345
                {
346
                    annotationTag.Sentiment = ETagSentiment.NEUTRAL;
347
                }
348

    
349
                // If for the same annotation exists a tag with same position and length and of the same type, ignore
350
                if (context.AnnotationTags.Any(at =>
351
                at.Position == annotationTag.Position &&
352
                at.Length == annotationTag.Length &&
353
                at.Annotation == annotation &&
354
                at.Tag == annotationTag.Tag))
355
                {
356
                    throw new InvalidOperationException("Duplicate tag");
357
                }
358

    
359
            }
360
            else if (request.Type == ETagType.SUBTAG)
361
            {
362
                var subTag = context.SubTags.Where(st => st.Id == request.Id).Include(st => st.Tag).Single();
363
                annotationTag.SubTag = subTag;
364
                annotationTag.Tag = subTag.Tag;
365

    
366
                if (annotationTag.SubTag.SentimentEnabled)
367
                {
368
                    annotationTag.Sentiment = ETagSentiment.NEUTRAL;
369
                }
370

    
371
                if (context.AnnotationTags.Any(at =>
372
                at.Position == annotationTag.Position &&
373
                at.Length == annotationTag.Length &&
374
                at.Annotation == annotation &&
375
                at.Tag == annotationTag.Tag &&
376
                at.SubTag == annotationTag.SubTag))
377
                {
378
                    throw new InvalidOperationException("Duplicate tag");
379
                }
380
            }
381
            else
382
            {
383
                throw new ArgumentException($"Unknown tag type {request.Type}");
384
            }
385

    
386
            if (annotation.State == EState.NEW)
387
            {
388
                annotation.State = EState.IN_PROGRESS;
389
            }
390

    
391
            annotation.LastModifiedTagId = annotationTag.Id;
392
            annotation.ModifiedType = EModified.ADDED;
393

    
394
            if (isFinal)
395
            {
396
                context.FinalAnnotationTags.Add(annotationTag as FinalAnnotationTag);
397
            }
398
            else
399
            {
400
                context.AnnotationTags.Add(annotationTag as AnnotationTag);
401
            }
402

    
403
            context.SaveChanges();
404
        }
405

    
406
        public void DeleteAnnotationInstance(Guid annotationId, Guid tagInstanceId, Guid loggedUserId, ERole userRole, bool isFinal)
407
        {
408
            Annotation annotation = null;
409
            try
410
            {
411
                if (!isFinal)
412
                {
413
                    annotation = context.Annotations
414
                    .Where(a => !(a is FinalAnnotation))
415
                    .Where(a => a.Id == annotationId)
416
                    .Include(a => a.User)
417
                    .Include(a => a.Document).ThenInclude(d => d.Content)
418
                    .First();
419
                }
420
                else
421
                {
422
                    annotation = context.FinalAnnotations
423
                    .Where(a => a.Id == annotationId)
424
                    .Include(a => a.User)
425
                    .Include(a => a.Document).ThenInclude(d => d.Content)
426
                    .First();
427
                }
428

    
429

    
430
            }
431
            catch (Exception ex)
432
            {
433
                throw new InvalidOperationException("Could not find annotation");
434
            }
435

    
436

    
437
            if (userRole < ERole.ADMINISTRATOR)
438
            {
439
                if (annotation.User.Id != loggedUserId)
440
                {
441
                    throw new UnauthorizedAccessException($"User {loggedUserId} does not have assigned annotation {annotationId}");
442
                }
443
            }
444

    
445
            AnnotationTagGeneric annotationTag = new();
446

    
447
            if (isFinal)
448
            {
449
                if (!context.FinalAnnotationTags.Any(at => at.Id == tagInstanceId))
450
                {
451
                    throw new InvalidOperationException("Could not find tag instance");
452
                }
453
                annotationTag = context.FinalAnnotationTags.First(at => at.Id == tagInstanceId);
454

    
455
            }
456
            else
457
            {
458
                if (!context.AnnotationTags.Any(at => at.Id == tagInstanceId))
459
                {
460
                    throw new InvalidOperationException("Could not find tag instance");
461
                }
462
                annotationTag = context.AnnotationTags.First(at => at.Id == tagInstanceId);
463
            }
464

    
465
            annotation.LastModifiedTagId = annotationTag.Id;
466
            annotation.ModifiedType = EModified.REMOVED;
467

    
468
            if (isFinal)
469
            {
470
                context.FinalAnnotationTags.Remove(annotationTag as FinalAnnotationTag);
471
            }
472
            else
473
            {
474
                context.AnnotationTags.Remove(annotationTag as AnnotationTag);
475
            }
476

    
477
            context.SaveChanges();
478
        }
479

    
480
        public void SetTagInstanceSentiment(Guid annotationId, Guid instanceId, Guid userId, ERole userRole, ETagSentiment sentiment, bool isFinal)
481
        {
482
            Annotation annotation = null;
483
            try
484
            {
485
                if (!isFinal)
486
                {
487
                    annotation = context.Annotations
488
                    .Where(a => !(a is FinalAnnotation))
489
                    .Where(a => a.Id == annotationId)
490
                    .Include(a => a.User)
491
                    .Include(a => a.Document).ThenInclude(d => d.Content)
492
                    .First();
493
                }
494
                else
495
                {
496
                    annotation = context.FinalAnnotations
497
                    .Where(a => a.Id == annotationId)
498
                    .Include(a => a.User)
499
                    .Include(a => a.Document).ThenInclude(d => d.Content)
500
                    .First();
501
                }
502
            }
503
            catch (Exception ex)
504
            {
505
                throw new InvalidOperationException("Could not find annotation");
506
            }
507

    
508

    
509
            if (userRole < ERole.ADMINISTRATOR)
510
            {
511
                if (annotation.User.Id != userId)
512
                {
513
                    throw new UnauthorizedAccessException($"User {userId} does not have assigned annotation {annotationId}");
514
                }
515
            }
516

    
517

    
518
            IEnumerable<AnnotationTagGeneric> tagInstances = null;
519

    
520
            if (isFinal)
521
            {
522
                tagInstances = context.FinalAnnotationTags.Where(at => at.Instance == instanceId).ToList();
523
            }
524
            else
525
            {
526
                tagInstances = context.AnnotationTags.Where(at => at.Instance == instanceId).ToList();
527
            }
528

    
529
            if (tagInstances.Count() == 0)
530
            {
531
                throw new InvalidOperationException("No such instance found");
532
            }
533

    
534
            foreach (var tagInstance in tagInstances)
535
            {
536
                tagInstance.Sentiment = sentiment;
537
            }
538

    
539
            context.SaveChanges();
540
        }
541

    
542
        public void MarkAnnotationAsDone(Guid annotationId, Guid userId, ERole userRole, bool done, bool isFinal)
543
        {
544

    
545
            Annotation annotation = null;
546
            try
547
            {
548
                if (!isFinal)
549
                {
550
                    annotation = context.Annotations
551
                    .Where(a => !(a is FinalAnnotation))
552
                   .Where(a => a.Id == annotationId)
553
                   .Include(a => a.User)
554
                   .Include(a => a.Document).ThenInclude(d => d.Content)
555
                   .First();
556
                }
557
                else
558
                {
559
                    annotation = context.FinalAnnotations
560
                   .Where(a => a.Id == annotationId)
561
                   .Include(a => a.User)
562
                   .Include(a => a.Document).ThenInclude(d => d.Content)
563
                   .First();
564
                }
565
            }
566
            catch (Exception ex)
567
            {
568
                throw new InvalidOperationException("Could not find annotation");
569
            }
570

    
571
            if (userRole < ERole.ADMINISTRATOR)
572
            {
573
                if (annotation.User.Id != userId)
574
                {
575
                    throw new UnauthorizedAccessException($"User {userId} does not have assigned annotation {annotationId}");
576
                }
577
            }
578

    
579
            annotation.State = done ? EState.DONE : EState.IN_PROGRESS;
580
            context.SaveChanges();
581
        }
582

    
583
        public Guid CreateFinalAnnotation(Guid documentId, Guid userId)
584
        {
585
            var document = context.Documents.Single(d => d.Id == documentId);
586
            var user = context.Users.Single(u => u.Id == userId);
587

    
588
            // Remove existing 
589
            if (context.FinalAnnotations.Any(fa => fa.Document == document))
590
            {
591
                var finalAnnotationOld = context.FinalAnnotations.Single(fa => fa.Document == document);
592
                context.FinalAnnotations.Remove(finalAnnotationOld);
593
            }
594

    
595
            var annotations = context.Annotations
596
                .Where(a => !(a is FinalAnnotation))
597
                .Include(a => a.Document)
598
                .Where(a => a.Document == document && a.State == EState.DONE)
599
                .ToList();
600

    
601
            var finalAnnotation = new FinalAnnotation()
602
            {
603
                Id = Guid.NewGuid(),
604
                DateAssigned = DateTime.Now,
605
                DateLastChanged = DateTime.Now,
606
                Document = document,
607
                User = user,
608
                UserAssigned = user,
609
                Annotations = annotations,
610
                State = EState.NEW
611
            };
612

    
613
            List<AnnotationTag> annotationTagsAll = new();
614
            foreach (var annotation in annotations)
615
            {
616
                annotationTagsAll.AddRange(context.AnnotationTags
617
                    .Where(at => at.Annotation == annotation)
618
                    .Include(at => at.Tag)
619
                    .Include(at => at.SubTag)
620
                    .Include(at => at.Annotation)
621
                    .ThenInclude(a => a.User)
622
                    .ToList());
623
            }
624
            annotationTagsAll = annotationTagsAll.OrderBy(at => at.Position).ToList();
625

    
626
            Dictionary<Guid, List<AnnotationTag>> occurenceDict = new();
627
            foreach (var annotationTag in annotationTagsAll)
628
            {
629
                if (occurenceDict.ContainsKey(annotationTag.Instance))
630
                {
631
                    occurenceDict[annotationTag.Instance].Add(annotationTag);
632
                }
633
                else
634
                {
635
                    occurenceDict[annotationTag.Instance] = new();
636
                    occurenceDict[annotationTag.Instance].Add(annotationTag);
637
                }
638
            }
639

    
640
            List<List<AnnotationTag>> occurenceLists = new();
641
            foreach (var key in occurenceDict.Keys)
642
            {
643
                occurenceLists.Add(occurenceDict[key]);
644
            }
645

    
646
            List<List<AnnotationTag>> annotationTagsProcessed = new();
647
            List<FinalAnnotationTag> finalAnnotationTags = new();
648
            for (int i = 0; i < occurenceLists.Count; i++)
649
            {
650
                var occurrenceList1 = occurenceLists[i];
651
                List<List<AnnotationTag>> sameLists = new();
652

    
653
                for (int j = 0; j < occurenceLists.Count; j++)
654
                {
655
                    var occurrenceList2 = occurenceLists[j];
656

    
657
                    if (annotationTagsProcessed.Contains(occurrenceList2))
658
                    {
659
                        continue;
660
                    }
661

    
662
                    if (SelectionsAreSame(occurrenceList1, occurrenceList2))
663
                    {
664
                        sameLists.Add(occurrenceList2);
665
                    }
666
                }
667

    
668
                // This means that this occurrence ahs already been processed as matching a previous tag
669
                if (sameLists.Count() == 0)
670
                {
671
                    continue;
672
                }
673

    
674
                List<User> relatedUsers = new();
675
                foreach (var list in sameLists)
676
                {
677
                    relatedUsers.Add(list[0].Annotation.User);
678
                }
679

    
680
                foreach (var tag in sameLists[0])
681
                {
682
                    finalAnnotationTags.Add(new()
683
                    {
684
                        Id = Guid.NewGuid(),
685
                        Tag = tag.Tag,
686
                        SubTag = tag.SubTag,
687
                        Annotation = finalAnnotation,
688
                        SelectedText = tag.SelectedText,
689
                        Sentiment = tag.Sentiment,
690
                        Instance = tag.Instance,
691
                        IsFinal = sameLists.Count == annotations.Count,
692
                        Length = tag.Length,
693
                        Position = tag.Position,
694
                        Note = "",
695
                        Users = relatedUsers
696
                    });
697
                }
698

    
699
                annotationTagsProcessed.AddRange(sameLists);
700
            }
701

    
702
            context.FinalAnnotations.Add(finalAnnotation);
703
            context.SaveChanges();
704
            context.FinalAnnotationTags.AddRange(finalAnnotationTags);
705

    
706
            context.SaveChanges();
707
            return finalAnnotation.Id;
708
        }
709

    
710
        private bool SelectionsAreSame(List<AnnotationTag> list1, List<AnnotationTag> list2)
711
        {
712
            if (list1.Count != list2.Count)
713
            {
714
                return false;
715
            }
716

    
717
            bool sentimentEnabled = list1[0].Tag.SentimentEnabled;
718

    
719
            if (sentimentEnabled)
720
            {
721
                for (int i = 0; i < list1.Count; i++)
722
                {
723
                    var tag1 = list1[i];
724
                    var tag2 = list2[i];
725
                    if (tag1.Position == tag2.Position &&
726
                        tag1.Length == tag2.Length &&
727
                        tag1.Sentiment == tag2.Sentiment &&
728
                        tag1.Tag == tag2.Tag &&
729
                        tag1.SubTag == tag2.SubTag)
730
                    {
731
                        continue;
732
                    }
733
                    else
734
                    {
735
                        return false;
736
                    }
737
                }
738
            }
739
            else
740
            {
741
                for (int i = 0; i < list1.Count; i++)
742
                {
743
                    var tag1 = list1[i];
744
                    var tag2 = list2[i];
745
                    if (tag1.Position == tag2.Position &&
746
                        tag1.Length == tag2.Length &&
747
                        tag1.Tag == tag2.Tag &&
748
                        tag1.SubTag == tag2.SubTag)
749
                    {
750
                        continue;
751
                    }
752
                    else
753
                    {
754
                        return false;
755
                    }
756
                }
757
            }
758

    
759
            return true;
760
        }
761

    
762
        public void SetTagIsFinal(Guid annotationId, Guid occurenceId, bool isFinal)
763
        {
764
            Annotation annotation;
765
            try
766
            {
767
                annotation = context.FinalAnnotations.Single(fa => fa.Id == annotationId);
768
            }
769
            catch (Exception)
770
            {
771
                throw new InvalidOperationException("Annotation not found");
772
            }
773

    
774
            FinalAnnotationTag finalTagInstance;
775
            try
776
            {
777
                finalTagInstance = context.FinalAnnotationTags.Single(fat => fat.Id == occurenceId);
778
            }
779
            catch (Exception)
780
            {
781
                throw new InvalidOperationException("Tag instance not found");
782
            }
783

    
784
            finalTagInstance.IsFinal = isFinal;
785

    
786
            context.SaveChanges();
787
        }
788
    }
789
}
(1-1/2)