Projekt

Obecné

Profil

Stáhnout (32.7 KB) Statistiky
| Větev: | Tag: | Revize:
1 eff8ec56 Vojtěch Bartička
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 6bdb3d95 Vojtěch Bartička
using Microsoft.EntityFrameworkCore;
12 a6675a6d Vojtěch Bartička
using AutoMapper;
13
using Models.Tags;
14 3c185841 Vojtěch Bartička
using Ganss.XSS;
15
using HtmlAgilityPack;
16
using System.Text.RegularExpressions;
17 553486ad Vojtěch Bartička
using Newtonsoft.Json;
18 8dc25caa Vojtěch Bartička
using Core.GraphUtils;
19 830652de Vojtěch Bartička
using Models.Documents;
20 eff8ec56 Vojtěch Bartička
21
namespace Core.Services.AnnotationService
22
{
23
    public class AnnotationServiceEF : IAnnotationService
24
    {
25
        private readonly DatabaseContext context;
26
        private readonly ILogger logger;
27 a6675a6d Vojtěch Bartička
        private readonly IMapper mapper;
28 2c9afc72 Vojtěch Bartička
        private readonly IHTMLService htmlService;
29 eff8ec56 Vojtěch Bartička
30 2c9afc72 Vojtěch Bartička
        public AnnotationServiceEF(DatabaseContext context, ILogger logger, IMapper mapper, IHTMLService htmlService)
31 eff8ec56 Vojtěch Bartička
        {
32
            this.context = context;
33
            this.logger = logger;
34 a6675a6d Vojtěch Bartička
            this.mapper = mapper;
35 2c9afc72 Vojtěch Bartička
            this.htmlService = htmlService;
36 eff8ec56 Vojtěch Bartička
        }
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 153d77a8 Vojtěch Bartička
            var documents = context.Documents.Where(d => request.DocumentIdList.Contains(d.Id)).ToList();
44
            if (documents.Count() != request.DocumentIdList.Count)
45 eff8ec56 Vojtěch Bartička
            {
46 153d77a8 Vojtěch Bartička
                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 eff8ec56 Vojtěch Bartička
            }
49
50 6bdb3d95 Vojtěch Bartička
            var users = context.Users.Where(u => request.UserIdList.Contains(u.Id)).ToList();
51 153d77a8 Vojtěch Bartička
            foreach (var user in users)
52 eff8ec56 Vojtěch Bartička
            {
53 8c9ce202 Vojtěch Bartička
                var userAnnotatedDocuments = context.Annotations
54
                    .Where(a => !(a is FinalAnnotation))
55
                    .Where(a => a.User == user)
56
                    .Select(a => a.Document)
57
                    .ToList();
58 153d77a8 Vojtěch Bartička
                foreach (var doc in documents)
59 eff8ec56 Vojtěch Bartička
                {
60 153d77a8 Vojtěch Bartička
                    if (userAnnotatedDocuments.Contains(doc))
61 eff8ec56 Vojtěch Bartička
                    {
62 153d77a8 Vojtěch Bartička
                        logger.Information($"User {user.Username} has already been assigned the document {doc.Id}, ignoring");
63
                        continue;
64 eff8ec56 Vojtěch Bartička
                    }
65
66
                    context.Annotations.Add(new Annotation()
67
                    {
68
                        User = user,
69
                        UserAssigned = addingUser,
70
                        DateAssigned = DateTime.Now,
71
                        DateLastChanged = DateTime.Now,
72 153d77a8 Vojtěch Bartička
                        Document = doc,
73 eff8ec56 Vojtěch Bartička
                        State = EState.NEW,
74
                        Note = ""
75
                    });
76
                }
77
            }
78
79
            context.SaveChanges();
80
        }
81 6bdb3d95 Vojtěch Bartička
82
        public AnnotationListResponse GetUserAnnotations(Guid userId)
83
        {
84 a49028dd Vojtěch Bartička
            var annotations = context.Annotations
85 8c9ce202 Vojtěch Bartička
                .Where(a => !(a is FinalAnnotation))
86 4a313c5d Vojtěch Bartička
                .Where(a => a.User.Id == userId)
87 a49028dd Vojtěch Bartička
                .Include(a => a.Document)
88
                .ToList();
89 8c9ce202 Vojtěch Bartička
90 6bdb3d95 Vojtěch Bartička
            var infos = new List<AnnotationListInfo>();
91 a49028dd Vojtěch Bartička
            foreach (var annotation in annotations)
92 6bdb3d95 Vojtěch Bartička
            {
93
                infos.Add(new AnnotationListInfo()
94
                {
95 a49028dd Vojtěch Bartička
                    AnnotationId = annotation.Id,
96
                    DocumentName = annotation.Document.Name,
97
                    State = annotation.State
98 6bdb3d95 Vojtěch Bartička
                });
99
            }
100
101
            return new AnnotationListResponse()
102
            {
103
                Annotations = infos
104
            };
105
        }
106 a6675a6d Vojtěch Bartička
107 83d4581e Vojtěch Bartička
        public void AddNoteToAnnotation(Guid annotationId, Guid userId, ERole userRole, AddNoteToAnnotationRequest request, bool isFinal)
108 f2275185 Vojtěch Bartička
        {
109
            Annotation annotation = null;
110
            try
111
            {
112 83d4581e Vojtěch Bartička
                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 f2275185 Vojtěch Bartička
            }
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 83d4581e Vojtěch Bartička
        public AnnotationInfo GetAnnotation(Guid annotationId, Guid userId, ERole userRole, bool isFinal)
137 a6675a6d Vojtěch Bartička
        {
138 83d4581e Vojtěch Bartička
            Annotation annotation = new();
139
            if (!isFinal)
140
            {
141
                annotation = context.Annotations
142 8c9ce202 Vojtěch Bartička
                .Where(a => !(a is FinalAnnotation))
143 83d4581e Vojtěch Bartička
                .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 c2a89232 Vojtěch Bartička
                .Where(a => a.Id == annotationId)
152
                .Include(a => a.User)
153
                .Include(a => a.Document).ThenInclude(d => d.Content)
154
                .First();
155 83d4581e Vojtěch Bartička
            }
156
157 3c185841 Vojtěch Bartička
158 a6675a6d Vojtěch Bartička
            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 c2a89232 Vojtěch Bartička
            var documentContent = context.Documents.Where(d => d.Id == annotation.Document.Id).Select(d => d.Content).First();
167 a6675a6d Vojtěch Bartička
168 8c9ce202 Vojtěch Bartička
            List<AnnotationTagGeneric> tags;
169
            if (!isFinal)
170
            {
171 6807d751 Vojtěch Bartička
                tags = context.AnnotationTags
172
                    .Where(at => at.Annotation.Id == annotationId)
173
                    .Include(at => at.Tag)
174
                    .ThenInclude(t => t.Category)
175
                    .Include(at => at.SubTag)
176
                    .OrderBy(at => at.Position)
177
                    .Select(at => at as AnnotationTagGeneric)
178
                    .ToList();
179 8c9ce202 Vojtěch Bartička
            }
180
            else
181
            {
182 6807d751 Vojtěch Bartička
                tags = context.FinalAnnotationTags
183
                    .Where(at => at.Annotation.Id == annotationId)
184
                    .Include(at => at.Users)
185
                    .Include(at => at.Tag)
186
                    .ThenInclude(t => t.Category)
187
                    .Include(at => at.SubTag)
188
                    .OrderBy(at => at.Position)
189
                    .Select(at => at as AnnotationTagGeneric)
190
                    .ToList();
191 8c9ce202 Vojtěch Bartička
            }
192
193 c2a89232 Vojtěch Bartička
194 0a9f9349 Vojtěch Bartička
            List<TagInstanceInfo> tagInstanceInfos = new();
195 a6675a6d Vojtěch Bartička
            foreach (var tag in tags)
196
            {
197 6807d751 Vojtěch Bartička
                if (!isFinal)
198
                {
199
                    var tagInstance = mapper.Map<TagInstanceInfo>(tag);
200
                    tagInstanceInfos.Add(tagInstance);
201
                }
202
                else
203
                {
204
                    var tagInstance = mapper.Map<TagInstanceInfo>(tag as FinalAnnotationTag);
205
                    tagInstanceInfos.Add(tagInstance);
206
                }
207
208 a6675a6d Vojtěch Bartička
            }
209
210 553486ad Vojtěch Bartička
            var docToRender = "";
211 83d4581e Vojtěch Bartička
            HTMLService.CachedInfo cachedInfoToReturn = new();
212 553486ad Vojtěch Bartička
            if (annotation.CachedDocumentHTML == "")
213
            {
214 2c9afc72 Vojtěch Bartička
                var result = htmlService.FullPreprocessHTML(documentContent.Content, tags);
215
                cachedInfoToReturn = result.Item2;
216
                docToRender = result.Item1;
217
218
                annotation.CachedStartPositions = JsonConvert.SerializeObject(cachedInfoToReturn.TagStartPositions);
219
                annotation.CachedLengths = JsonConvert.SerializeObject(cachedInfoToReturn.TagStartLengths);
220
                annotation.CachedClosingPositions = JsonConvert.SerializeObject(cachedInfoToReturn.TagClosingPositions);
221
                annotation.CachedClosingLengths = JsonConvert.SerializeObject(cachedInfoToReturn.TagClosingLengths);
222
                annotation.CachedCSS = JsonConvert.SerializeObject(cachedInfoToReturn.TagInstanceCSS);
223 553486ad Vojtěch Bartička
                annotation.ModifiedType = EModified.NONE;
224
                annotation.CachedDocumentHTML = docToRender;
225
                context.SaveChanges();
226
            }
227
            else
228
            {
229
                docToRender = annotation.CachedDocumentHTML;
230 ceadebfe Vojtěch Bartička
                cachedInfoToReturn = new()
231 2c9afc72 Vojtěch Bartička
                {
232
                    TagStartPositions = JsonConvert.DeserializeObject<List<int>>(annotation.CachedStartPositions),
233
                    TagStartLengths = JsonConvert.DeserializeObject<List<int>>(annotation.CachedLengths),
234
                    TagClosingPositions = JsonConvert.DeserializeObject<List<int>>(annotation.CachedClosingPositions),
235 ceadebfe Vojtěch Bartička
                    TagClosingLengths = JsonConvert.DeserializeObject<List<int>>(annotation.CachedClosingLengths),
236
                    TagInstanceCSS = JsonConvert.DeserializeObject<List<TagInstanceCSSInfo>>(annotation.CachedCSS)
237 2c9afc72 Vojtěch Bartička
                };
238 83d4581e Vojtěch Bartička
239 553486ad Vojtěch Bartička
                // The annotation has been modified and we need to either add the new tag or remove the tag
240
                if (annotation.ModifiedType != EModified.NONE)
241
                {
242
                    if (annotation.ModifiedType == EModified.ADDED)
243
                    {
244 f260dac8 Vojtěch Bartička
245 6807d751 Vojtěch Bartička
                        AnnotationTagGeneric lastModifiedTag = isFinal ? context.FinalAnnotationTags.Where(at => at.Id == annotation.LastModifiedTagId).First() :
246 f260dac8 Vojtěch Bartička
                            context.AnnotationTags.Where(at => at.Id == annotation.LastModifiedTagId).First();
247
248 ceadebfe Vojtěch Bartička
                        var result = htmlService.PartialPreprocessHTMLAddTag(docToRender, documentContent.Content, lastModifiedTag, tags, cachedInfoToReturn);
249 2c9afc72 Vojtěch Bartička
                        docToRender = result.Item1;
250
                        cachedInfoToReturn = result.Item2;
251 553486ad Vojtěch Bartička
                    }
252
                    else if (annotation.ModifiedType == EModified.REMOVED)
253
                    {
254 ceadebfe Vojtěch Bartička
                        var result = htmlService.PartialPreprocessHTMLRemoveTag(docToRender, documentContent.Content, new AnnotationTag() { Id = annotation.LastModifiedTagId.Value }, tags, cachedInfoToReturn);
255 2c9afc72 Vojtěch Bartička
                        docToRender = result.Item1;
256
                        cachedInfoToReturn = result.Item2;
257 553486ad Vojtěch Bartička
                    }
258
259
                    annotation.ModifiedType = EModified.NONE;
260 2c9afc72 Vojtěch Bartička
                    annotation.CachedStartPositions = JsonConvert.SerializeObject(cachedInfoToReturn.TagStartPositions);
261
                    annotation.CachedLengths = JsonConvert.SerializeObject(cachedInfoToReturn.TagStartLengths);
262
                    annotation.CachedClosingPositions = JsonConvert.SerializeObject(cachedInfoToReturn.TagClosingPositions);
263
                    annotation.CachedClosingLengths = JsonConvert.SerializeObject(cachedInfoToReturn.TagClosingLengths);
264 553486ad Vojtěch Bartička
                    annotation.CachedDocumentHTML = docToRender;
265 2c9afc72 Vojtěch Bartička
                    annotation.CachedCSS = JsonConvert.SerializeObject(cachedInfoToReturn.TagInstanceCSS);
266 553486ad Vojtěch Bartička
                    context.SaveChanges();
267
                }
268
            }
269 0a9f9349 Vojtěch Bartička
270
            // We probably cannot use AutoMapper since we are dealing with too many different entities
271
            AnnotationInfo annotationInfo = new()
272
            {
273
                SourceDocumentContent = documentContent.Content,
274
                DocumentToRender = docToRender,
275 2c9afc72 Vojtěch Bartička
                TagStartPositions = cachedInfoToReturn.TagStartPositions.ToArray(),
276
                TagLengths = cachedInfoToReturn.TagStartLengths.ToArray(),
277 0a9f9349 Vojtěch Bartička
                Note = annotation.Note,
278
                State = annotation.State,
279
                Type = IsHtml(documentContent.Content) ? EDocumentType.HTML : EDocumentType.TEXT,
280 26671569 Vojtěch Bartička
                TagInstances = tagInstanceInfos,
281 2c9afc72 Vojtěch Bartička
                CSSInfo = cachedInfoToReturn.TagInstanceCSS
282 0a9f9349 Vojtěch Bartička
            };
283
284 a6675a6d Vojtěch Bartička
            return annotationInfo;
285
        }
286
287
        // TODO temporary
288
        private bool IsHtml(string text)
289
        {
290 0a9f9349 Vojtěch Bartička
            return text.Contains("<html>");
291 a6675a6d Vojtěch Bartička
        }
292 be4deff8 Vojtěch Bartička
293 83d4581e Vojtěch Bartička
        public void AddAnnotationInstance(Guid annotationId, Guid userId, ERole userRole, AnnotationInstanceAddRequest request, bool isFinal)
294 be4deff8 Vojtěch Bartička
        {
295 83d4581e Vojtěch Bartička
            Annotation annotation = new();
296
            if (!isFinal)
297
            {
298
                annotation = context.Annotations
299 8c9ce202 Vojtěch Bartička
                    .Where(a => !(a is FinalAnnotation))
300 83d4581e Vojtěch Bartička
                    .Where(a => a.Id == annotationId)
301
                    .Include(a => a.User)
302
                    .Include(a => a.Document).ThenInclude(d => d.Content)
303
                    .First();
304
            }
305
            else
306
            {
307
                annotation = context.FinalAnnotations
308
                    .Where(a => a.Id == annotationId)
309
                    .Include(a => a.User)
310
                    .Include(a => a.Document).ThenInclude(d => d.Content)
311
                    .First();
312
            }
313 be4deff8 Vojtěch Bartička
314
            if (userRole < ERole.ADMINISTRATOR)
315
            {
316
                if (annotation.User.Id != userId)
317
                {
318
                    throw new UnauthorizedAccessException($"User {userId} does not have assigned annotation {annotationId}");
319
                }
320
            }
321
322 83d4581e Vojtěch Bartička
            if (annotation.State == EState.NEW)
323 82dede50 Vojtěch Bartička
            {
324 83d4581e Vojtěch Bartička
                annotation.State = EState.IN_PROGRESS;
325
            }
326
327
            AnnotationTagGeneric annotationTag = new();
328
            if (isFinal)
329
            {
330
                annotationTag = new FinalAnnotationTag()
331
                {
332
                    Id = Guid.NewGuid(),
333
                    Annotation = annotation as FinalAnnotation,
334
                    Instance = request.InstanceId == null ? Guid.NewGuid() : request.InstanceId.Value,
335
                    Length = request.Length,
336
                    Position = request.Position,
337
                    SelectedText = request.SelectedText,
338 f260dac8 Vojtěch Bartička
                    Note = "",
339
                    IsFinal = true
340 83d4581e Vojtěch Bartička
                };
341
            }
342
            else
343
            {
344
                annotationTag = new AnnotationTag()
345
                {
346
                    Id = Guid.NewGuid(),
347
                    Annotation = annotation as Annotation,
348
                    Instance = request.InstanceId == null ? Guid.NewGuid() : request.InstanceId.Value,
349
                    Length = request.Length,
350
                    Position = request.Position,
351
                    SelectedText = request.SelectedText,
352
                    Note = ""
353
                };
354
            }
355 be4deff8 Vojtěch Bartička
356
            if (request.Type == ETagType.TAG)
357
            {
358
                annotationTag.Tag = context.Tags.Where(t => t.Id == request.Id).Single();
359
                annotationTag.SubTag = null;
360 15c88dc1 Vojtěch Bartička
361
                if (annotationTag.Tag.SentimentEnabled)
362
                {
363
                    annotationTag.Sentiment = ETagSentiment.NEUTRAL;
364
                }
365 2f3821f0 Vojtěch Bartička
366 58363b44 Vojtěch Bartička
                // If for the same annotation exists a tag with same position and length and of the same type, ignore
367 2f3821f0 Vojtěch Bartička
                if (context.AnnotationTags.Any(at =>
368 58363b44 Vojtěch Bartička
                at.Position == annotationTag.Position &&
369
                at.Length == annotationTag.Length &&
370
                at.Annotation == annotation &&
371
                at.Tag == annotationTag.Tag))
372
                {
373
                    throw new InvalidOperationException("Duplicate tag");
374
                }
375
376 be4deff8 Vojtěch Bartička
            }
377
            else if (request.Type == ETagType.SUBTAG)
378
            {
379
                var subTag = context.SubTags.Where(st => st.Id == request.Id).Include(st => st.Tag).Single();
380
                annotationTag.SubTag = subTag;
381
                annotationTag.Tag = subTag.Tag;
382 15c88dc1 Vojtěch Bartička
383
                if (annotationTag.SubTag.SentimentEnabled)
384
                {
385
                    annotationTag.Sentiment = ETagSentiment.NEUTRAL;
386
                }
387 2f3821f0 Vojtěch Bartička
388
                if (context.AnnotationTags.Any(at =>
389 58363b44 Vojtěch Bartička
                at.Position == annotationTag.Position &&
390
                at.Length == annotationTag.Length &&
391
                at.Annotation == annotation &&
392
                at.Tag == annotationTag.Tag &&
393
                at.SubTag == annotationTag.SubTag))
394
                {
395
                    throw new InvalidOperationException("Duplicate tag");
396
                }
397 be4deff8 Vojtěch Bartička
            }
398
            else
399
            {
400
                throw new ArgumentException($"Unknown tag type {request.Type}");
401
            }
402
403 ceadebfe Vojtěch Bartička
            if (annotation.State == EState.NEW)
404
            {
405
                annotation.State = EState.IN_PROGRESS;
406
            }
407
408 553486ad Vojtěch Bartička
            annotation.LastModifiedTagId = annotationTag.Id;
409
            annotation.ModifiedType = EModified.ADDED;
410
411 83d4581e Vojtěch Bartička
            if (isFinal)
412
            {
413
                context.FinalAnnotationTags.Add(annotationTag as FinalAnnotationTag);
414
            }
415
            else
416
            {
417
                context.AnnotationTags.Add(annotationTag as AnnotationTag);
418
            }
419
420 be4deff8 Vojtěch Bartička
            context.SaveChanges();
421
        }
422 0f8d6304 Vojtěch Bartička
423 83d4581e Vojtěch Bartička
        public void DeleteAnnotationInstance(Guid annotationId, Guid tagInstanceId, Guid loggedUserId, ERole userRole, bool isFinal)
424 0f8d6304 Vojtěch Bartička
        {
425
            Annotation annotation = null;
426
            try
427
            {
428 83d4581e Vojtěch Bartička
                if (!isFinal)
429
                {
430
                    annotation = context.Annotations
431 8c9ce202 Vojtěch Bartička
                    .Where(a => !(a is FinalAnnotation))
432 83d4581e Vojtěch Bartička
                    .Where(a => a.Id == annotationId)
433
                    .Include(a => a.User)
434
                    .Include(a => a.Document).ThenInclude(d => d.Content)
435
                    .First();
436
                }
437
                else
438
                {
439
                    annotation = context.FinalAnnotations
440
                    .Where(a => a.Id == annotationId)
441
                    .Include(a => a.User)
442
                    .Include(a => a.Document).ThenInclude(d => d.Content)
443
                    .First();
444
                }
445
446 0f8d6304 Vojtěch Bartička
447
            }
448
            catch (Exception ex)
449
            {
450
                throw new InvalidOperationException("Could not find annotation");
451
            }
452
453
454
            if (userRole < ERole.ADMINISTRATOR)
455
            {
456
                if (annotation.User.Id != loggedUserId)
457
                {
458
                    throw new UnauthorizedAccessException($"User {loggedUserId} does not have assigned annotation {annotationId}");
459
                }
460
            }
461
462 83d4581e Vojtěch Bartička
            AnnotationTagGeneric annotationTag = new();
463
464
            if (isFinal)
465 0f8d6304 Vojtěch Bartička
            {
466 83d4581e Vojtěch Bartička
                if (!context.FinalAnnotationTags.Any(at => at.Id == tagInstanceId))
467
                {
468
                    throw new InvalidOperationException("Could not find tag instance");
469
                }
470
                annotationTag = context.FinalAnnotationTags.First(at => at.Id == tagInstanceId);
471 0f8d6304 Vojtěch Bartička
472 83d4581e Vojtěch Bartička
            }
473
            else
474
            {
475
                if (!context.AnnotationTags.Any(at => at.Id == tagInstanceId))
476
                {
477
                    throw new InvalidOperationException("Could not find tag instance");
478
                }
479
                annotationTag = context.AnnotationTags.First(at => at.Id == tagInstanceId);
480
            }
481 553486ad Vojtěch Bartička
482
            annotation.LastModifiedTagId = annotationTag.Id;
483
            annotation.ModifiedType = EModified.REMOVED;
484
485 83d4581e Vojtěch Bartička
            if (isFinal)
486
            {
487
                context.FinalAnnotationTags.Remove(annotationTag as FinalAnnotationTag);
488
            }
489
            else
490
            {
491
                context.AnnotationTags.Remove(annotationTag as AnnotationTag);
492
            }
493 0a9f9349 Vojtěch Bartička
494 0f8d6304 Vojtěch Bartička
            context.SaveChanges();
495
        }
496 15c88dc1 Vojtěch Bartička
497 83d4581e Vojtěch Bartička
        public void SetTagInstanceSentiment(Guid annotationId, Guid instanceId, Guid userId, ERole userRole, ETagSentiment sentiment, bool isFinal)
498 15c88dc1 Vojtěch Bartička
        {
499
            Annotation annotation = null;
500
            try
501
            {
502 83d4581e Vojtěch Bartička
                if (!isFinal)
503
                {
504
                    annotation = context.Annotations
505 8c9ce202 Vojtěch Bartička
                    .Where(a => !(a is FinalAnnotation))
506 83d4581e Vojtěch Bartička
                    .Where(a => a.Id == annotationId)
507
                    .Include(a => a.User)
508
                    .Include(a => a.Document).ThenInclude(d => d.Content)
509
                    .First();
510
                }
511
                else
512
                {
513
                    annotation = context.FinalAnnotations
514
                    .Where(a => a.Id == annotationId)
515
                    .Include(a => a.User)
516
                    .Include(a => a.Document).ThenInclude(d => d.Content)
517
                    .First();
518
                }
519 15c88dc1 Vojtěch Bartička
            }
520
            catch (Exception ex)
521
            {
522
                throw new InvalidOperationException("Could not find annotation");
523
            }
524
525
526
            if (userRole < ERole.ADMINISTRATOR)
527
            {
528
                if (annotation.User.Id != userId)
529
                {
530
                    throw new UnauthorizedAccessException($"User {userId} does not have assigned annotation {annotationId}");
531
                }
532
            }
533
534
535 83d4581e Vojtěch Bartička
            IEnumerable<AnnotationTagGeneric> tagInstances = null;
536
537
            if (isFinal)
538
            {
539
                tagInstances = context.FinalAnnotationTags.Where(at => at.Instance == instanceId).ToList();
540
            }
541
            else
542
            {
543
                tagInstances = context.AnnotationTags.Where(at => at.Instance == instanceId).ToList();
544
            }
545
546 15c88dc1 Vojtěch Bartička
            if (tagInstances.Count() == 0)
547
            {
548
                throw new InvalidOperationException("No such instance found");
549
            }
550
551
            foreach (var tagInstance in tagInstances)
552
            {
553
                tagInstance.Sentiment = sentiment;
554
            }
555
556
            context.SaveChanges();
557
        }
558 0ea30313 Vojtěch Bartička
559 83d4581e Vojtěch Bartička
        public void MarkAnnotationAsDone(Guid annotationId, Guid userId, ERole userRole, bool done, bool isFinal)
560 0ea30313 Vojtěch Bartička
        {
561 83d4581e Vojtěch Bartička
562 0ea30313 Vojtěch Bartička
            Annotation annotation = null;
563
            try
564
            {
565 83d4581e Vojtěch Bartička
                if (!isFinal)
566
                {
567
                    annotation = context.Annotations
568 8c9ce202 Vojtěch Bartička
                    .Where(a => !(a is FinalAnnotation))
569 0ea30313 Vojtěch Bartička
                   .Where(a => a.Id == annotationId)
570
                   .Include(a => a.User)
571
                   .Include(a => a.Document).ThenInclude(d => d.Content)
572
                   .First();
573 83d4581e Vojtěch Bartička
                }
574
                else
575
                {
576
                    annotation = context.FinalAnnotations
577
                   .Where(a => a.Id == annotationId)
578
                   .Include(a => a.User)
579
                   .Include(a => a.Document).ThenInclude(d => d.Content)
580
                   .First();
581
                }
582 0ea30313 Vojtěch Bartička
            }
583
            catch (Exception ex)
584
            {
585
                throw new InvalidOperationException("Could not find annotation");
586
            }
587
588
            if (userRole < ERole.ADMINISTRATOR)
589
            {
590
                if (annotation.User.Id != userId)
591
                {
592
                    throw new UnauthorizedAccessException($"User {userId} does not have assigned annotation {annotationId}");
593
                }
594
            }
595
596
            annotation.State = done ? EState.DONE : EState.IN_PROGRESS;
597
            context.SaveChanges();
598
        }
599 440997e0 Vojtěch Bartička
600
        public Guid CreateFinalAnnotation(Guid documentId, Guid userId)
601
        {
602
            var document = context.Documents.Single(d => d.Id == documentId);
603
            var user = context.Users.Single(u => u.Id == userId);
604
605
            // Remove existing 
606
            if (context.FinalAnnotations.Any(fa => fa.Document == document))
607
            {
608
                var finalAnnotationOld = context.FinalAnnotations.Single(fa => fa.Document == document);
609
                context.FinalAnnotations.Remove(finalAnnotationOld);
610
            }
611
612
            var annotations = context.Annotations
613 8c9ce202 Vojtěch Bartička
                .Where(a => !(a is FinalAnnotation))
614 440997e0 Vojtěch Bartička
                .Include(a => a.Document)
615
                .Where(a => a.Document == document && a.State == EState.DONE)
616
                .ToList();
617
618
            var finalAnnotation = new FinalAnnotation()
619
            {
620
                Id = Guid.NewGuid(),
621
                DateAssigned = DateTime.Now,
622
                DateLastChanged = DateTime.Now,
623
                Document = document,
624
                User = user,
625
                UserAssigned = user,
626
                Annotations = annotations,
627
                State = EState.NEW
628
            };
629
630
            List<AnnotationTag> annotationTagsAll = new();
631
            foreach (var annotation in annotations)
632
            {
633
                annotationTagsAll.AddRange(context.AnnotationTags
634
                    .Where(at => at.Annotation == annotation)
635
                    .Include(at => at.Tag)
636
                    .Include(at => at.SubTag)
637
                    .Include(at => at.Annotation)
638
                    .ThenInclude(a => a.User)
639
                    .ToList());
640
            }
641
            annotationTagsAll = annotationTagsAll.OrderBy(at => at.Position).ToList();
642
643
            Dictionary<Guid, List<AnnotationTag>> occurenceDict = new();
644
            foreach (var annotationTag in annotationTagsAll)
645
            {
646
                if (occurenceDict.ContainsKey(annotationTag.Instance))
647
                {
648
                    occurenceDict[annotationTag.Instance].Add(annotationTag);
649
                }
650
                else
651
                {
652
                    occurenceDict[annotationTag.Instance] = new();
653
                    occurenceDict[annotationTag.Instance].Add(annotationTag);
654
                }
655
            }
656
657
            List<List<AnnotationTag>> occurenceLists = new();
658
            foreach (var key in occurenceDict.Keys)
659
            {
660
                occurenceLists.Add(occurenceDict[key]);
661
            }
662
663
            List<List<AnnotationTag>> annotationTagsProcessed = new();
664
            List<FinalAnnotationTag> finalAnnotationTags = new();
665
            for (int i = 0; i < occurenceLists.Count; i++)
666
            {
667
                var occurrenceList1 = occurenceLists[i];
668
                List<List<AnnotationTag>> sameLists = new();
669
670
                for (int j = 0; j < occurenceLists.Count; j++)
671
                {
672
                    var occurrenceList2 = occurenceLists[j];
673
674
                    if (annotationTagsProcessed.Contains(occurrenceList2))
675
                    {
676
                        continue;
677
                    }
678
679
                    if (SelectionsAreSame(occurrenceList1, occurrenceList2))
680
                    {
681
                        sameLists.Add(occurrenceList2);
682
                    }
683
                }
684
685
                // This means that this occurrence ahs already been processed as matching a previous tag
686
                if (sameLists.Count() == 0)
687
                {
688
                    continue;
689
                }
690
691
                List<User> relatedUsers = new();
692
                foreach (var list in sameLists)
693
                {
694
                    relatedUsers.Add(list[0].Annotation.User);
695
                }
696
697
                foreach (var tag in sameLists[0])
698
                {
699
                    finalAnnotationTags.Add(new()
700
                    {
701
                        Id = Guid.NewGuid(),
702
                        Tag = tag.Tag,
703
                        SubTag = tag.SubTag,
704
                        Annotation = finalAnnotation,
705
                        SelectedText = tag.SelectedText,
706
                        Sentiment = tag.Sentiment,
707
                        Instance = tag.Instance,
708
                        IsFinal = sameLists.Count == annotations.Count,
709
                        Length = tag.Length,
710
                        Position = tag.Position,
711
                        Note = "",
712
                        Users = relatedUsers
713
                    });
714
                }
715
716
                annotationTagsProcessed.AddRange(sameLists);
717
            }
718
719
            context.FinalAnnotations.Add(finalAnnotation);
720
            context.SaveChanges();
721
            context.FinalAnnotationTags.AddRange(finalAnnotationTags);
722
723
            context.SaveChanges();
724
            return finalAnnotation.Id;
725
        }
726
727
        private bool SelectionsAreSame(List<AnnotationTag> list1, List<AnnotationTag> list2)
728
        {
729
            if (list1.Count != list2.Count)
730
            {
731
                return false;
732
            }
733
734
            bool sentimentEnabled = list1[0].Tag.SentimentEnabled;
735
736
            if (sentimentEnabled)
737
            {
738
                for (int i = 0; i < list1.Count; i++)
739
                {
740
                    var tag1 = list1[i];
741
                    var tag2 = list2[i];
742
                    if (tag1.Position == tag2.Position &&
743
                        tag1.Length == tag2.Length &&
744
                        tag1.Sentiment == tag2.Sentiment &&
745
                        tag1.Tag == tag2.Tag &&
746
                        tag1.SubTag == tag2.SubTag)
747
                    {
748
                        continue;
749
                    }
750
                    else
751
                    {
752
                        return false;
753
                    }
754
                }
755
            }
756
            else
757
            {
758
                for (int i = 0; i < list1.Count; i++)
759
                {
760
                    var tag1 = list1[i];
761
                    var tag2 = list2[i];
762
                    if (tag1.Position == tag2.Position &&
763
                        tag1.Length == tag2.Length &&
764
                        tag1.Tag == tag2.Tag &&
765
                        tag1.SubTag == tag2.SubTag)
766
                    {
767
                        continue;
768
                    }
769
                    else
770
                    {
771
                        return false;
772
                    }
773
                }
774
            }
775
776
            return true;
777
        }
778 f2e3b199 Vojtěch Bartička
779 f260dac8 Vojtěch Bartička
        public void SetTagIsFinal(Guid annotationId, Guid occurenceId, bool isFinal)
780
        {
781
            Annotation annotation;
782
            try
783
            {
784
                annotation = context.FinalAnnotations.Single(fa => fa.Id == annotationId);
785
            }
786
            catch (Exception)
787
            {
788
                throw new InvalidOperationException("Annotation not found");
789
            }
790
791
            FinalAnnotationTag finalTagInstance;
792
            try
793
            {
794
                finalTagInstance = context.FinalAnnotationTags.Single(fat => fat.Id == occurenceId);
795
            }
796
            catch (Exception)
797
            {
798
                throw new InvalidOperationException("Tag instance not found");
799
            }
800
801
            finalTagInstance.IsFinal = isFinal;
802
803
            context.SaveChanges();
804
        }
805 830652de Vojtěch Bartička
806
        public MemoryStream Export(ExportRequest request)
807
        {
808
            // Get documents
809 f2e3b199 Vojtěch Bartička
            var documentsToExport = context.Documents
810
                .Include(d => d.Content)
811 77f4265e Vojtěch Bartička
                .Where(d => request.DocumentIds.Contains(d.Id))
812
                .ToList();
813 830652de Vojtěch Bartička
814
            // Get annotations
815
            Dictionary<Document, List<Annotation>> annotationsToExport = new();
816
            foreach (var document in documentsToExport)
817
            {
818
                annotationsToExport[document] = context.Annotations
819
                    .Where(a => a.Document == document && a.State == EState.DONE)
820
                    .Include(a => a.Document)
821
                    .Include(a => a.User)
822
                    .ToList();
823
            }
824
825
            // Get final annotations
826
            Dictionary<Document, FinalAnnotation> finalAnnotationsToExport = new();
827
            foreach (var document in documentsToExport)
828
            {
829
                if (!context.FinalAnnotations.Any(fa => fa.Document == document))
830
                {
831
                    finalAnnotationsToExport[document] = null;
832
                }
833
                else
834
                {
835
                    finalAnnotationsToExport[document] = context.FinalAnnotations
836
                        .Single(fa => fa.Document == document);
837
                }
838
            }
839
840
            // Get tags for each annotation
841
            Dictionary<Annotation, List<AnnotationTag>> tagsToExport = new();
842
            foreach (var document in annotationsToExport.Keys)
843
            {
844
                foreach (var annotation in annotationsToExport[document])
845
                {
846
                    tagsToExport[annotation] = context.AnnotationTags
847
                        .Include(at => at.Annotation)
848
                        .Include(at => at.Tag).ThenInclude(t => t.Category)
849
                        .Include(at => at.SubTag)
850
                        .Where(at => at.Annotation == annotation)
851
                        .ToList();
852
                }
853
            }
854
855
            // Get tags for each final annotation
856
            Dictionary<FinalAnnotation, List<FinalAnnotationTag>> finalTagsToExport = new();
857
            foreach (var document in finalAnnotationsToExport.Keys)
858
            {
859
                var finalAnnotation = finalAnnotationsToExport[document];
860 baf6fc22 Vojtěch Bartička
                if (finalAnnotation == null)
861
                {
862
                    continue;
863
                }
864
865 830652de Vojtěch Bartička
                finalTagsToExport[finalAnnotation] = context.FinalAnnotationTags
866
                    .Include(at => at.Annotation)
867
                    .Include(at => at.Tag).ThenInclude(t => t.Category)
868
                    .Include(at => at.SubTag)
869
                    .Where(at => at.Annotation == finalAnnotation)
870
                    .ToList();
871
            }
872
873
            MemoryStream output = ZipUtils.Export.FullExport(documentsToExport.ToList(), annotationsToExport, finalAnnotationsToExport, tagsToExport, finalTagsToExport);
874
            return output;
875
        }
876 eff8ec56 Vojtěch Bartička
    }
877
}