using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Security.Principal; using System.Threading.Tasks; using BO.AppServer.Business.Exceptions; using BO.AppServer.Business.Mapper; using BO.AppServer.Business.Services.Base; using BO.AppServer.Data.Entity; using BO.AppServer.Data.Repository; using BO.AppServer.Metadata.Dto; using BO.AppServer.Metadata.Enums; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Quadarax.Foundation.Core.Data; using Quadarax.Foundation.Core.Data.Interface; using Quadarax.Foundation.Core.Data.Interface.Entity.Dto; namespace BO.AppServer.Business.Services { public class DocumentService : UserContextService { #region *** Private fields *** private WorkspaceRepo _repoWorkspace; private MetadocumentRepo _repoDocument; private MimeTypeRepo _repoMType; private ArtifactRepo _repoArtifact; private StorageService _srvStorage; #endregion #region *** Constructors *** public DocumentService( WorkspaceRepo repoWorkspace, MetadocumentRepo repoDocument, MimeTypeRepo repoMType, ArtifactRepo repoArtifact, IOptions config, UserRepo repoUser, UserManager userManager, IPrincipal currentPrincipal, ILoggerFactory logger) : base(config, repoUser, userManager, currentPrincipal, logger) { _repoWorkspace = repoWorkspace ?? throw new ArgumentNullException(nameof(repoWorkspace)); _repoDocument = repoDocument ?? throw new ArgumentNullException(nameof(repoDocument)); _repoMType = repoMType ?? throw new ArgumentNullException(nameof(repoMType)); _repoArtifact = repoArtifact ?? throw new ArgumentNullException(nameof(repoArtifact)); } #endregion #region *** Public Operations *** public async Task> GetDocumentAsync(long workspaceId, long documentId) { var document = CheckAndGetDocument(workspaceId, documentId); return new ResultValueDto(document.Map()); } public async Task> GetAllDocumentsAsync(long workspaceId, DocumentsScopeEnums scope, PagingDto paging) { CheckAndGetWorkspace(workspaceId); IList documents = new List(); switch (scope) { case DocumentsScopeEnums.All: documents = _repoDocument.Query(paging).Where(x => x.Structure.WorkspaceId == workspaceId).OrderBy(x => x.Name).ToList(); break; case DocumentsScopeEnums.Pending: documents = _repoDocument.Query(paging).Where(x => x.Structure.WorkspaceId == workspaceId && x.Status == (int)DocumentStatusEnum.Pending).OrderBy(x => x.Name).ToList(); break; case DocumentsScopeEnums.Done: documents = _repoDocument.Query(paging).Where(x => x.Structure.WorkspaceId == workspaceId && x.Status == (int)DocumentStatusEnum.DoneOk).OrderBy(x => x.Name).ToList(); break; case DocumentsScopeEnums.Working: documents = _repoDocument.Query(paging).Where(x => x.Structure.WorkspaceId == workspaceId && x.Status == (int)DocumentStatusEnum.Processing).OrderBy(x => x.Name).ToList(); break; case DocumentsScopeEnums.Failed: documents = _repoDocument.Query(paging).Where(x => x.Structure.WorkspaceId == workspaceId && x.Status == (int)DocumentStatusEnum.DoneFail).OrderBy(x => x.Name).ToList(); break; } return new ResultsValueDto(documents.MapList()); } public async Task> GetAllDocumentsAsync(DocumentsScopeEnums scope, PagingDto paging) { IList documents = new List(); switch (scope) { case DocumentsScopeEnums.All: documents = _repoDocument.Query(paging).OrderBy(x => x.Name).ToList(); break; case DocumentsScopeEnums.Pending: documents = _repoDocument.Query(paging).Where(x => x.Status == (int)DocumentStatusEnum.Pending).OrderBy(x => x.Name).ToList(); break; case DocumentsScopeEnums.Done: documents = _repoDocument.Query(paging).Where(x => x.Status == (int)DocumentStatusEnum.DoneOk).OrderBy(x => x.Name).ToList(); break; case DocumentsScopeEnums.Working: documents = _repoDocument.Query(paging).Where(x => x.Status == (int)DocumentStatusEnum.Processing).OrderBy(x => x.Name).ToList(); break; case DocumentsScopeEnums.Failed: documents = _repoDocument.Query(paging).Where(x => x.Status == (int)DocumentStatusEnum.DoneFail).OrderBy(x => x.Name).ToList(); break; } return new ResultsValueDto(documents.MapList()); } public async Task> CreateDocumentAsync(long workspaceId, DocumentCDto document) { var workspace = CheckAndGetWorkspace(workspaceId); var exists = _repoDocument.Query(new Paging()) .Any(x => x.Structure.WorkspaceId == workspaceId && x.Name == document.Name); if (exists) { var exc = new EntityAlreadyExistsException(typeof(Metadocument), document.Name); Log.LogWarning(exc.Message); throw exc; } var newDocument = _repoDocument.New(); document.CopyToDto(newDocument); newDocument.Created = DateTime.Now; newDocument.CreatedByUser = GetCurrentUser(); newDocument.Status = (int)DocumentStatusEnum.New; newDocument.StructureId = workspace.Structures.First().Id; _repoDocument.Set(newDocument); _repoDocument.Commit(); return new ResultValueDto(newDocument.Map()); } public async Task> AppendArtifactAsync(long workspaceId, long documentId, ArtifactCDto artifact, ArtifactTypeEnum type, Stream content) { //TODO: Rewrite better way - mainly rollback scenario var document = CheckAndGetDocument(workspaceId, documentId); var exists = document.Artifacts.Any(x => x.Name.ToLower() == artifact.Name.ToLower() && x.Extension.ToLower() == artifact.Extension.ToLower()); if (exists) { var exc = new EntityAlreadyExistsException(typeof(Artifact), artifact.Name + "." + artifact.Extension); Log.LogWarning(exc.Message); throw exc; } var mtype = _repoMType.GetByMimeType(artifact.MimeType); if (mtype == null) { var exc = new EntityNotExistsException(typeof(MimeType), artifact.MimeType, 0); Log.LogWarning(exc.Message); throw exc; } var newArtifact = _repoArtifact.New(); newArtifact.Name = artifact.Name; newArtifact.Extension = artifact.Extension; newArtifact.Length = content.Length; newArtifact.Metadocument = document; newArtifact.MimeType = mtype; newArtifact.Created = DateTime.Now; newArtifact.CreatedByUser = GetCurrentUser(); newArtifact.Type = (int)type; _repoArtifact.Set(newArtifact); document = _repoDocument.Get(documentId); document.Modified = DateTime.Now; document.ModifiedByUser = GetCurrentUser(); _repoDocument.Set(document); _repoArtifact.Commit(); _repoDocument.Commit(); await _srvStorage.PushContentAsync(newArtifact.Id, content); return new ResultValueDto(newArtifact.Map()); } public async Task> GetArtifactAsync(long workspaceId, long documentId, long artifactId) { var artifact = CheckAndGetArtifact(workspaceId, documentId, artifactId); var result = await _srvStorage.PopContentAsync(artifact.Id); return new Tuple(result.Item1, artifact.MimeType.Mimetype1); } #endregion #region *** Private Operations *** private Workspace CheckAndGetWorkspace(long workspaceId) { var workspace = _repoWorkspace.Get(workspaceId); if (workspace == null) { var exc = new EntityNotExistsException(typeof(Workspace), nameof(Workspace.Id), workspaceId); Log.LogWarning(exc.Message); throw exc; } return workspace; } private Metadocument CheckAndGetDocument(long workspaceId, long documentId) { CheckAndGetWorkspace(workspaceId); var document = _repoDocument.Get(workspaceId ,documentId); if (document == null) { var exc = new EntityNotExistsException(typeof(Metadocument), nameof(Metadocument.Id), documentId); Log.LogWarning(exc.Message); throw exc; } return document; } private Artifact CheckAndGetArtifact(long workspaceId, long documentId, long artifactId) { CheckAndGetWorkspace(workspaceId); CheckAndGetDocument(workspaceId, documentId); var artifact = _repoDocument.GetArtifact(documentId, artifactId); if (artifact == null) { var exc = new EntityNotExistsException(typeof(Artifact), nameof(Artifact.Id), artifactId); Log.LogWarning(exc.Message); throw exc; } return artifact; } #endregion } }