using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; using Newtonsoft.Json; using RMuseum.Models.Artifact; using RMuseum.Models.Artifact.ViewModels; using RMuseum.Models.Auth.Memory; using RMuseum.Models.Bookmark; using RMuseum.Models.Bookmark.ViewModels; using RMuseum.Models.GanjoorIntegration; using RMuseum.Models.GanjoorIntegration.ViewModels; using RMuseum.Models.ImportJob; using RMuseum.Models.Note; using RMuseum.Models.Note.ViewModels; using RMuseum.Services; using RSecurityBackend.Models.Auth.Memory; using RSecurityBackend.Models.Generic; using RSecurityBackend.Services; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Threading.Tasks; namespace RMuseum.Controllers { [Produces("application/json")] [Route("api/artifacts")] public class ArtifactController : Controller { /// /// get all published artifacts (including CoverImage info but not items info) /// /// /// [HttpGet] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task Get([FromQuery]PagingParameterModel paging) { var cacheKey = $"artifacts/all/{paging.PageSize}/{paging.PageNumber}"; if (!_memoryCache.TryGetValue(cacheKey, out RServiceResult<(PaginationMetadata PagingMeta, RArtifactMasterRecord[] Items)> itemsInfo)) { itemsInfo = await _artifactService.GetAll(paging, new PublishStatus[] { PublishStatus.Published }); if (!string.IsNullOrEmpty(itemsInfo.ExceptionString)) { return BadRequest(itemsInfo.ExceptionString); } _memoryCache.Set(cacheKey, itemsInfo); } if(itemsInfo.Result.Items.Count() > 0) { DateTime lastModification = itemsInfo.Result.Items.Max(i => i.LastModified); Response.GetTypedHeaders().LastModified = lastModification; var requestHeaders = Request.GetTypedHeaders(); if (requestHeaders.IfModifiedSince.HasValue && requestHeaders.IfModifiedSince.Value >= lastModification) { return StatusCode(StatusCodes.Status304NotModified); } } // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(itemsInfo.Result.PagingMeta)); return Ok(itemsInfo.Result.Items); } /// /// get list of artifact statuses user can see /// /// /// /// private async Task> _GetUserVisibleArtifactStatusSet(Guid loggedOnUserId, Guid sessionId) { RServiceResult canView = await _userPermissionChecker.Check ( loggedOnUserId, sessionId, RMuseumSecurableItem.ArtifactEntityShortName, RMuseumSecurableItem.ViewDraftOperationShortName ); if (!string.IsNullOrEmpty(canView.ExceptionString)) return new RServiceResult(null, canView.ExceptionString); PublishStatus[] visibleItems = canView.Result ? new PublishStatus[] { PublishStatus.Published, PublishStatus.Restricted, PublishStatus.Draft, PublishStatus.Awaiting } : new PublishStatus[] { PublishStatus.Published }; return new RServiceResult(visibleItems); } /// /// get all artifacts visible by user (including CoverImage info but not items info) /// /// /// [HttpGet] [Route("secure")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetUserVisible([FromQuery]PagingParameterModel paging) { RServiceResult v = await _GetUserVisibleArtifactStatusSet ( new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value), new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value) ); if (!string.IsNullOrEmpty(v.ExceptionString)) return BadRequest(v.ExceptionString); PublishStatus[] visibleItems = v.Result; if (visibleItems.Length == 1 && visibleItems[0] == PublishStatus.Published) //Caching { return await Get(paging); } RServiceResult<(PaginationMetadata PagingMeta, RArtifactMasterRecord[] Items)> itemsInfo = await _artifactService.GetAll(paging, visibleItems); if (!string.IsNullOrEmpty(itemsInfo.ExceptionString)) { return BadRequest(itemsInfo.ExceptionString); } if (itemsInfo.Result.Items.Count() > 0) { DateTime lastModification = itemsInfo.Result.Items.Max(i => i.LastModified); Response.GetTypedHeaders().LastModified = lastModification; var requestHeaders = Request.GetTypedHeaders(); if (requestHeaders.IfModifiedSince.HasValue && requestHeaders.IfModifiedSince.Value >= lastModification) { return StatusCode(StatusCodes.Status304NotModified); } } // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(itemsInfo.Result.PagingMeta)); return Ok(itemsInfo.Result.Items); } [HttpGet("tagged/{tagUrl}/{valueUrl}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetByTagValue(string tagUrl, string valueUrl) { RServiceResult itemsInfo = await _artifactService.GetByTagValue(tagUrl, valueUrl, new PublishStatus[] { PublishStatus.Published } ); if (!string.IsNullOrEmpty(itemsInfo.ExceptionString)) { return BadRequest(itemsInfo.ExceptionString); } if (itemsInfo.Result.Length > 0) { DateTime lastModification = itemsInfo.Result.Max(i => i.LastModified); Response.GetTypedHeaders().LastModified = lastModification; var requestHeaders = Request.GetTypedHeaders(); if (requestHeaders.IfModifiedSince.HasValue && requestHeaders.IfModifiedSince.Value >= lastModification) { return StatusCode(StatusCodes.Status304NotModified); } } return Ok(itemsInfo.Result); } /// /// gets specified publish artifact info (including CoverImage + images) /// /// /// [HttpGet("{friendlyUrl}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RArtifactMasterRecordViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task Get(string friendlyUrl) { var cacheKey = $"artifacts/friendlyUrl/{friendlyUrl}"; if (!_memoryCache.TryGetValue(cacheKey, out RServiceResult itemInfo)) { itemInfo = await _artifactService.GetByFriendlyUrl(friendlyUrl, new PublishStatus[] { PublishStatus.Published }); if (!string.IsNullOrEmpty(itemInfo.ExceptionString)) { return BadRequest(itemInfo.ExceptionString); } if (itemInfo.Result == null) return NotFound(); _memoryCache.Set(cacheKey, itemInfo); } Response.GetTypedHeaders().LastModified = itemInfo.Result.LastModified; var requestHeaders = Request.GetTypedHeaders(); if (requestHeaders.IfModifiedSince.HasValue && requestHeaders.IfModifiedSince.Value >= itemInfo.Result.LastModified) { return StatusCode(StatusCodes.Status304NotModified); } return Ok(itemInfo.Result); } /// /// remove unpublished artifact having no notes and not bookmarked /// /// /// [HttpDelete("{artifactId}")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + SecurableItem.DeleteOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task RemoveArtifactHavingNoNoteAndBookmarks(Guid artifactId) { RServiceResult res = await _artifactService.RemoveArtifactHavingNoNoteAndBookmarks(artifactId, true); if (!string.IsNullOrEmpty(res.ExceptionString)) { return BadRequest(res.ExceptionString); } return Ok(res.Result); } /// /// gets specified publish artifact info (including CoverImage + images) where its items are filteted by tag /// /// /// /// [HttpGet("{friendlyUrl}/filteritemsbytag/{tagFriendlyUrl}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RArtifactMasterRecordViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetByFriendlyUrlFilterItemsByTag(string friendlyUrl, string tagFriendlyUrl) { return await GetByFriendlyUrlFilterItemsByTag(friendlyUrl, tagFriendlyUrl, null); } /// /// gets specified publish artifact info (including CoverImage + images) where its items are filteted by tag /// /// /// /// /// [HttpGet("{friendlyUrl}/filteritemsbytag/{tagFriendlyUrl}/{valueFriendlyUrl}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RArtifactMasterRecordViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetByFriendlyUrlFilterItemsByTag(string friendlyUrl, string tagFriendlyUrl, string valueFriendlyUrl) { var cacheKey = $"{friendlyUrl}/filteritemsbytag/{tagFriendlyUrl}"; if(valueFriendlyUrl != null) { cacheKey += $"/{valueFriendlyUrl}"; } if (!_memoryCache.TryGetValue(cacheKey, out RServiceResult itemInfo)) { itemInfo = await _artifactService.GetByFriendlyUrlFilterItemsByTag(friendlyUrl, new PublishStatus[] { PublishStatus.Published }, tagFriendlyUrl, valueFriendlyUrl); if (!string.IsNullOrEmpty(itemInfo.ExceptionString)) { return BadRequest(itemInfo.ExceptionString); } if (itemInfo.Result == null) return NotFound(); _memoryCache.Set(cacheKey, itemInfo); } Response.GetTypedHeaders().LastModified = itemInfo.Result.LastModified; var requestHeaders = Request.GetTypedHeaders(); if (requestHeaders.IfModifiedSince.HasValue && requestHeaders.IfModifiedSince.Value >= itemInfo.Result.LastModified) { return StatusCode(StatusCodes.Status304NotModified); } return Ok(itemInfo.Result); } /// /// gets specified publish artifact info (including CoverImage + images) /// /// /// [HttpGet("secure/{friendlyUrl}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RArtifactMasterRecordViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetUserVisible(string friendlyUrl) { RServiceResult v = await _GetUserVisibleArtifactStatusSet ( new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value), new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value) ); if (!string.IsNullOrEmpty(v.ExceptionString)) return BadRequest(v.ExceptionString); PublishStatus[] visibleItems = v.Result; RServiceResult itemInfo = null; if (visibleItems.Length == 1 && visibleItems[0] == PublishStatus.Published) { var cacheKey = $"artifacts/friendlyUrl/{friendlyUrl}"; if (!_memoryCache.TryGetValue(cacheKey, out itemInfo)) { itemInfo = await _artifactService.GetByFriendlyUrl(friendlyUrl, new PublishStatus[] { PublishStatus.Published }); if (!string.IsNullOrEmpty(itemInfo.ExceptionString)) { return BadRequest(itemInfo.ExceptionString); } if (itemInfo.Result == null) return NotFound(); _memoryCache.Set(cacheKey, itemInfo); } } if(itemInfo == null) { itemInfo = await _artifactService.GetByFriendlyUrl(friendlyUrl, visibleItems); } if (!string.IsNullOrEmpty(itemInfo.ExceptionString)) { return BadRequest(itemInfo.ExceptionString); } if (itemInfo.Result == null) return NotFound(); Response.GetTypedHeaders().LastModified = itemInfo.Result.LastModified; var requestHeaders = Request.GetTypedHeaders(); if (requestHeaders.IfModifiedSince.HasValue && requestHeaders.IfModifiedSince.Value >= itemInfo.Result.LastModified) { return StatusCode(StatusCodes.Status304NotModified); } return Ok(itemInfo.Result); } /// /// gets specified publish artifact info (including CoverImage + images) where its items are filteted by tag /// /// /// /// [HttpGet("secure/{friendlyUrl}/filteritemsbytag/{tagFriendlyUrl}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RArtifactMasterRecordViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetUserVisibleByFriendlyUrlFilterItemsByTag(string friendlyUrl, string tagFriendlyUrl) { return await GetUserVisibleByFriendlyUrlFilterItemsByTag(friendlyUrl, tagFriendlyUrl, null); } /// /// gets specified publish artifact info (including CoverImage + images) where its items are filteted by tag /// /// /// /// /// [HttpGet("secure/{friendlyUrl}/filteritemsbytag/{tagFriendlyUrl}/{valueFriendlyUrl}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RArtifactMasterRecordViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetUserVisibleByFriendlyUrlFilterItemsByTag(string friendlyUrl, string tagFriendlyUrl, string valueFriendlyUrl) { RServiceResult v = await _GetUserVisibleArtifactStatusSet ( new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value), new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value) ); if (!string.IsNullOrEmpty(v.ExceptionString)) return BadRequest(v.ExceptionString); PublishStatus[] visibleItems = v.Result; if(visibleItems.Length == 1 && visibleItems[0] == PublishStatus.Published) { return await GetByFriendlyUrlFilterItemsByTag(friendlyUrl, tagFriendlyUrl, valueFriendlyUrl); } RServiceResult itemInfo = await _artifactService.GetByFriendlyUrlFilterItemsByTag(friendlyUrl, visibleItems, tagFriendlyUrl, valueFriendlyUrl); if (!string.IsNullOrEmpty(itemInfo.ExceptionString)) { return BadRequest(itemInfo.ExceptionString); } if (itemInfo.Result == null) return NotFound(); Response.GetTypedHeaders().LastModified = itemInfo.Result.LastModified; var requestHeaders = Request.GetTypedHeaders(); if (requestHeaders.IfModifiedSince.HasValue && requestHeaders.IfModifiedSince.Value >= itemInfo.Result.LastModified) { return StatusCode(StatusCodes.Status304NotModified); } return Ok(itemInfo.Result); } /// /// edit artifactt master record (user should have additional permissions artifact:awaiting and artifact:publish to change status of artifact) /// /// /// editing related collections such as images and attributed or complex properties such as CoverImage is ignored /// /// /// /// [HttpPut("{id}")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task Put(Guid id, [FromBody]RArtifactMasterRecord item) { if (id != item.Id) { return BadRequest(); } Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); Guid sessionId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value); RServiceResult canChangeStatusToAwaiting = await _userPermissionChecker.Check ( loggedOnUserId, sessionId, RMuseumSecurableItem.ArtifactEntityShortName, RMuseumSecurableItem.ToAwaitingStatusOperationShortName ); if (!string.IsNullOrEmpty(canChangeStatusToAwaiting.ExceptionString)) return BadRequest(canChangeStatusToAwaiting.ExceptionString); RServiceResult canPublish = await _userPermissionChecker.Check ( loggedOnUserId, sessionId, RMuseumSecurableItem.ArtifactEntityShortName, RMuseumSecurableItem.PublishOperationShortName ); if (!string.IsNullOrEmpty(canPublish.ExceptionString)) return BadRequest(canPublish.ExceptionString); RServiceResult itemInfo = await _artifactService.EditMasterRecord(item, canChangeStatusToAwaiting.Result, canPublish.Result); if (!string.IsNullOrEmpty(itemInfo.ExceptionString)) { return BadRequest(itemInfo.ExceptionString); } if(itemInfo == null) { return NotFound(); } return Ok();; } /// /// Set Artifact Cover Item Index /// /// /// /// [HttpPut("{id}/cover")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task SetArtifactCoverItemIndex(Guid id, [FromBody]int itemIndex) { RServiceResult res = await _artifactService.SetArtifactCoverItemIndex(id, itemIndex); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(); return Ok(); } /// /// get tag bundle by frindly url /// /// /// [HttpGet("tagbundle/{friendlyUrl}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RTagBundleViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetTagBundleByFiendlyUrl(string friendlyUrl) { var cacheKey = $"tagbundle/{friendlyUrl}"; if (!_memoryCache.TryGetValue(cacheKey, out RServiceResult tag)) { tag = await _artifactService.GetTagBundleByFiendlyUrl(friendlyUrl); if (!string.IsNullOrEmpty(tag.ExceptionString)) { return BadRequest(tag.ExceptionString); } if (tag.Result == null) return NotFound(); _memoryCache.Set(cacheKey, tag); } RServiceResult lastModified = await _artifactService.GetMaxArtifactLastModified(); if(!string.IsNullOrEmpty(lastModified.ExceptionString)) { return BadRequest(lastModified.ExceptionString); } DateTime lastModification = lastModified.Result; Response.GetTypedHeaders().LastModified = lastModification; var requestHeaders = Request.GetTypedHeaders(); if (requestHeaders.IfModifiedSince.HasValue && requestHeaders.IfModifiedSince.Value >= lastModification) { return StatusCode(StatusCodes.Status304NotModified); } return Ok(tag.Result); } /// /// add new tag /// /// only name is processed /// [HttpPost("tag")] [Authorize(Policy = RMuseumSecurableItem.TagEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RTag))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task NewTag([FromBody]RTag tag) { RServiceResult res = await _artifactService.AddTag(tag.Name); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// get all tags /// /// /// [HttpGet("tag")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetTags([FromQuery]PagingParameterModel paging) { RServiceResult<(PaginationMetadata PagingMeta, RTag[] Items)> itemsInfo = await _artifactService.GetAllTags(paging); if (!string.IsNullOrEmpty(itemsInfo.ExceptionString)) { return BadRequest(itemsInfo.ExceptionString); } // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(itemsInfo.Result.PagingMeta)); return Ok(itemsInfo.Result.Items); } [HttpGet("tag/{friendlyUrl}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RTag))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetTagByFriendlyUrl(string friendlyUrl) { RServiceResult tag = await _artifactService.GetTagByFriendlyUrl(friendlyUrl); if (!string.IsNullOrEmpty(tag.ExceptionString)) { return BadRequest(tag.ExceptionString); } return Ok(tag.Result); } /// /// edit tag /// /// /// editable fields are limited /// /// /// /// [HttpPut("tag/{tagid}")] [Authorize(Policy = RMuseumSecurableItem.TagEntityShortName + ":" + SecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task PutTag(Guid tagid, [FromBody]RTag tag) { if (tagid != tag.Id) { return BadRequest(); } RServiceResult itemInfo = await _artifactService.EditTag(tag); if (!string.IsNullOrEmpty(itemInfo.ExceptionString)) { return BadRequest(itemInfo.ExceptionString); } if (itemInfo == null) { return NotFound(); } return Ok();; } /// /// changes order of tags based on their position in artifacts /// /// /// /// up / down /// the other tag which its Order got replaced with the input id [HttpPut("tag/move/{tagid}/in/{artifactId}/{upordown}")] [Authorize(Policy = RMuseumSecurableItem.TagEntityShortName + ":" + RMuseumSecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(Guid))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task MoveTag(Guid tagId, Guid artifactId, string upordown) { RServiceResult otherTagId = await _artifactService.EditTagOrderBasedOnArtifact(tagId, artifactId, upordown == "up"); if (!string.IsNullOrEmpty(otherTagId.ExceptionString)) { return BadRequest(otherTagId.ExceptionString); } return Ok((Guid)otherTagId.Result); } /// /// changes order of tags based on their position in artifact items /// /// /// /// up / down /// the other tag which its Order got replaced with the input id [HttpPut("tag/move/{tagid}/in/item/{itemId}/{upordown}")] [Authorize(Policy = RMuseumSecurableItem.TagEntityShortName + ":" + RMuseumSecurableItem.ModifyOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(Guid))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task MoveTagInItem(Guid tagId, Guid itemId, string upordown) { RServiceResult otherTagId = await _artifactService.EditTagOrderBasedOnItem(tagId, itemId, upordown == "up"); if (!string.IsNullOrEmpty(otherTagId.ExceptionString)) { return BadRequest(otherTagId.ExceptionString); } return Ok((Guid)otherTagId.Result); } /// /// get tag value bundle by frindly url /// /// /// /// [HttpGet("tagbundle/{friendlyUrl}/{valueUrl}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RArtifactTagViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetTagValueBundleByFiendlyUrl(string friendlyUrl, string valueUrl) { RServiceResult tag = await _artifactService.GetTagValueBundleByFiendlyUrl(friendlyUrl, valueUrl); if (!string.IsNullOrEmpty(tag.ExceptionString)) { return BadRequest(tag.ExceptionString); } if (tag.Result == null) return NotFound(); return Ok(tag.Result); } /// /// get tag value by frindly url /// /// /// /// [HttpGet("tagvalue/{tagId}/{friendlyUrl}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RTagValue))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetTagValueByFriendlyUrl(Guid tagId, string friendlyUrl) { RServiceResult tag = await _artifactService.GetTagValueByFriendlyUrl(tagId, friendlyUrl); if (!string.IsNullOrEmpty(tag.ExceptionString)) { return BadRequest(tag.ExceptionString); } return Ok(tag.Result); } /// /// add new tag value to artifact /// /// /// only name is processed /// [HttpPost("tagvalue/{artifactid}")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + RMuseumSecurableItem.EditTagValueOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RTagValue))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task NewArtifactTagValue(Guid artifactId, [FromBody]RTag tag) { RServiceResult res = await _artifactService.TagArtifact(artifactId, tag); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// edit artifact attribute value /// /// /// editable fields are limited /// /// /// /// apply on all same value tags /// [HttpPut("tagvalue/{artifactid}/{global=true}")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + RMuseumSecurableItem.EditTagValueOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task PutAttributeValue(Guid artifactid, bool global, [FromBody]RTagValue tagvalue) { RServiceResult itemInfo = await _artifactService.EditTagValue(artifactid, tagvalue, global); if (!string.IsNullOrEmpty(itemInfo.ExceptionString)) { return BadRequest(itemInfo.ExceptionString); } if (itemInfo == null) { return NotFound(); } return Ok();; } /// /// remove tag from artifact /// /// /// /// [HttpDelete("tagvalue/{artifactId}/{tagValueId}")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + RMuseumSecurableItem.EditTagValueOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task RemoveArtifactTagValue(Guid artifactId, Guid tagValueId) { RServiceResult res = await _artifactService.UnTagArtifact(artifactId, tagValueId); if (!string.IsNullOrEmpty(res.ExceptionString)) { return BadRequest(res.ExceptionString); } return Ok(res.Result); } /// /// add new tag value to item /// /// /// only name is processed /// [HttpPost("itemtagvalue/{itemId}")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + RMuseumSecurableItem.EditTagValueOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RTagValue))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task NewItemTagValue(Guid itemId, [FromBody]RTag tag) { RServiceResult res = await _artifactService.TagItem(itemId, tag); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// edit item attribute value /// /// /// editable fields are limited /// /// /// /// apply on all same value tags /// [HttpPut("itemtagvalue/{itemId}/{global=true}")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + RMuseumSecurableItem.EditTagValueOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task PutItemTagValue(Guid itemId, bool global, [FromBody]RTagValue tagvalue) { RServiceResult itemInfo = await _artifactService.EditItemTagValue(itemId, tagvalue, global); if (!string.IsNullOrEmpty(itemInfo.ExceptionString)) { return BadRequest(itemInfo.ExceptionString); } if (itemInfo == null) { return NotFound(); } return Ok();; } /// /// remove tag from item /// /// /// /// [HttpDelete("itemtagvalue/{itemId}/{tagValueId}")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + RMuseumSecurableItem.EditTagValueOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.Forbidden)] public async Task RemoveItemTagValue(Guid itemId, Guid tagValueId) { RServiceResult res = await _artifactService.UnTagItem(itemId, tagValueId); if (!string.IsNullOrEmpty(res.ExceptionString)) { return BadRequest(res.ExceptionString); } return Ok(res.Result); } /// /// changes order of tag values based on their position in an artifact /// /// /// /// /// up / down /// the other tag which its Order got replaced with the input id [HttpPut("tagvalue/{artifactid}/{tagId}/{valueId}/move/{upordown}")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + RMuseumSecurableItem.EditTagValueOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(Guid))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task MoveTagValue(Guid artifactId, Guid tagId, Guid valueId, string upordown) { RServiceResult otherValueId = await _artifactService.EditTagValueOrder(artifactId, tagId, valueId, upordown == "up"); if (!string.IsNullOrEmpty(otherValueId.ExceptionString)) { return BadRequest(otherValueId.ExceptionString); } return Ok((Guid)otherValueId.Result); } /// /// changes order of tag values based on their position in an item /// /// /// /// /// up / down /// the other tag which its Order got replaced with the input id [HttpPut("itemtagvalue/{itemId}/{tagId}/{valueId}/move/{upordown}")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + RMuseumSecurableItem.EditTagValueOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(Guid))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task MoveItemTagValue(Guid itemId, Guid tagId, Guid valueId, string upordown) { RServiceResult otherValueId = await _artifactService.EditItemTagValueOrder(itemId, tagId, valueId, upordown == "up"); if (!string.IsNullOrEmpty(otherValueId.ExceptionString)) { return BadRequest(otherValueId.ExceptionString); } return Ok((Guid)otherValueId.Result); } /// /// gets specified publish artifact item info (including images + attributes) /// /// /// /// [HttpGet("{artifactUrl}/{itemUrl}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RArtifactItemRecordViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetArtifactItemByFrienlyUrl(string artifactUrl, string itemUrl) { RServiceResult itemInfo = await _artifactService.GetArtifactItemByFrienlyUrl(artifactUrl, itemUrl, new PublishStatus[] { PublishStatus.Published }); if (!string.IsNullOrEmpty(itemInfo.ExceptionString)) { return BadRequest(itemInfo.ExceptionString); } if (itemInfo.Result == null) return NotFound(); Response.GetTypedHeaders().LastModified = itemInfo.Result.Item.LastModified; var requestHeaders = Request.GetTypedHeaders(); if (requestHeaders.IfModifiedSince.HasValue && requestHeaders.IfModifiedSince.Value >= itemInfo.Result.Item.LastModified) { return StatusCode(StatusCodes.Status304NotModified); } return Ok(itemInfo.Result); } /// /// gets specified publish artifact item info (including images + attributes) /// /// /// /// [HttpGet("secure/{artifactUrl}/{itemUrl}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RArtifactItemRecordViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] [ProducesResponseType((int)HttpStatusCode.NotFound)] public async Task GetArtifactItemByFrienlyUrlUserVisible(string artifactUrl, string itemUrl) { RServiceResult v = await _GetUserVisibleArtifactStatusSet ( new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value), new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value) ); if (!string.IsNullOrEmpty(v.ExceptionString)) return BadRequest(v.ExceptionString); PublishStatus[] visibleItems = v.Result; RServiceResult itemInfo = await _artifactService.GetArtifactItemByFrienlyUrl(artifactUrl, itemUrl, visibleItems); if (!string.IsNullOrEmpty(itemInfo.ExceptionString)) { return BadRequest(itemInfo.ExceptionString); } if (itemInfo.Result == null) return NotFound(); Response.GetTypedHeaders().LastModified = itemInfo.Result.Item.LastModified; var requestHeaders = Request.GetTypedHeaders(); if (requestHeaders.IfModifiedSince.HasValue && requestHeaders.IfModifiedSince.Value >= itemInfo.Result.Item.LastModified) { return StatusCode(StatusCodes.Status304NotModified); } return Ok(itemInfo.Result); } /// /// Add new artifact (multipart/form-data) /// /// /// const data = new FormData(); /// data.append('name', 'تست'); /// data.append('description', ''); /// data.append('srcUrl', ''); /// data.append('picTitle', 'تست'); /// data.append('picDescription', ''); /// data.append('file', this.file); /// data.append('picSrcUrl', ''); /// /// /// /// [HttpPost] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + SecurableItem.AddOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RArtifactMasterRecord))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public virtual async Task Post() { try { NewArtifact newArtifactInfo = new NewArtifact() { Name = Request.Form["name"], Description = Request.Form["description"], SrcUrl = Request.Form["srcUrl"], PicTitle = Request.Form["picTitle"], PicDescription = Request.Form["picDescription"], File = Request.Form.Files[0], PicSrcUrl = Request.Form["picSrcUrl"] }; RServiceResult result = await _artifactService.Add ( newArtifactInfo.Name, newArtifactInfo.Description, newArtifactInfo.SrcUrl, newArtifactInfo.PicTitle, newArtifactInfo.PicDescription, newArtifactInfo.File, newArtifactInfo.PicSrcUrl, null); if (result.Result == null) return BadRequest(result.ExceptionString); return Ok(result.Result); } catch(Exception exp) { return BadRequest(exp.ToString()); } } /// /// import from external resources /// /// loc/princeton/harvard/qajarwomen/hathitrust/penn/cam/bl/folder/walters/cbl /// 119 /// golestan-baysonghori /// /// [HttpPost] [Route("import")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + RMuseumSecurableItem.ImportOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task Import(string srcType, string resourceNumber, string friendlyUrl, string resourcePrefix) { RServiceResult res = await _artifactService.Import(srcType, resourceNumber, friendlyUrl, resourcePrefix); if (res.Result) return Ok(); return BadRequest(res.ExceptionString); } /// /// keep alive (for import background service) /// /// true [HttpGet] [Route("keep-alive")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(bool))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public IActionResult KeepAlive() { return Ok(true); } /// /// retry import /// /// [HttpPost] [Route("retryimport")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + RMuseumSecurableItem.ImportOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task RetryImport() { RServiceResult res = await _artifactService.RescheduleJobs(); if (res.Result) return Ok(); return BadRequest(res.ExceptionString); } /// /// due to a bug in loc json outputs some artifacts with more than 1000 pages were downloaded incompletely /// /// 123456 /// [HttpPost] [Route("reexamineimport")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + RMuseumSecurableItem.ImportOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(string[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task ReExamineLocDownloads(string pass) { if(pass != "123456") //this is a heavy processor consuming call, so prevent mistaken call of it from swagger ui return BadRequest("invalid password"); RServiceResult res = await _artifactService.ReExamineLocDownloads(); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } [HttpGet] [Route("jobs")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + SecurableItem.AddOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(IEnumerable))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetImportJobs([FromQuery]PagingParameterModel paging) { RServiceResult<(PaginationMetadata PagingMeta, ImportJob[] Items)> itemsInfo = await _artifactService.GetImportJobs(paging); if (!string.IsNullOrEmpty(itemsInfo.ExceptionString)) { return BadRequest(itemsInfo.ExceptionString); } // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(itemsInfo.Result.PagingMeta)); return Ok(itemsInfo.Result.Items); } /// /// bookmark artifact /// /// /// [HttpPost] [Route("bookmark/{artifactId}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserBookmark))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task BookmarkArtifact(Guid artifactId) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _artifactService.BookmarkArtifact(artifactId, loggedOnUserId, RBookmarkType.Bookmark); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// bookmark item /// /// /// [HttpPost] [Route("bookmark/item/{itemId}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserBookmark))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task BookmarkItem(Guid itemId) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _artifactService.BookmarkItem(itemId, loggedOnUserId, RBookmarkType.Bookmark); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// item bookmarks info /// /// /// [HttpDelete] [Route("bookmark/{bookmarkId}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task DeleteBookmark(Guid bookmarkId) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _artifactService.DeleteUserBookmark(bookmarkId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok();; } /// /// fav artifact /// /// /// [HttpPost] [Route("fav/{artifactId}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserBookmark))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task FavArtifact(Guid artifactId) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _artifactService.BookmarkArtifact(artifactId, loggedOnUserId, RBookmarkType.Favorite); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// fav item /// /// /// [HttpPost] [Route("fav/item/{itemId}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserBookmark))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task FavItem(Guid itemId) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _artifactService.BookmarkItem(itemId, loggedOnUserId, RBookmarkType.Favorite); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// artifact bookmarks info /// /// /// [HttpGet] [Route("bookmark/{artifactId}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserBookmark[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GeIArtifactUserBookmarks(Guid artifactId) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _artifactService.GetArtifactUserBookmarks(artifactId, loggedOnUserId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// item bookmarks info /// /// /// [HttpGet] [Route("bookmark/item/{itemId}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserBookmark[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GeItemUserBookmarks(Guid itemId) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _artifactService.GeItemUserBookmarks(itemId, loggedOnUserId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// user bookmarks /// /// [HttpGet] [Route("bookmark")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserBookmark[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetUserBookmarks([FromQuery]PagingParameterModel paging) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult v = await _GetUserVisibleArtifactStatusSet ( loggedOnUserId, new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value) ); if (!string.IsNullOrEmpty(v.ExceptionString)) return BadRequest(v.ExceptionString); PublishStatus[] visibleItems = v.Result; RServiceResult<(PaginationMetadata PagingMeta, RUserBookmarkViewModel[] Bookmarks)> res = await _artifactService.GetBookmarks(paging, loggedOnUserId, RBookmarkType.Bookmark, visibleItems); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(res.Result.PagingMeta)); return Ok(res.Result.Bookmarks); } /// /// user favorites /// /// [HttpGet] [Route("fav")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserBookmarkViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetUserFavorites([FromQuery]PagingParameterModel paging) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult v = await _GetUserVisibleArtifactStatusSet ( loggedOnUserId, new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value) ); if (!string.IsNullOrEmpty(v.ExceptionString)) return BadRequest(v.ExceptionString); PublishStatus[] visibleItems = v.Result; RServiceResult<(PaginationMetadata PagingMeta, RUserBookmarkViewModel[] Bookmarks)> res = await _artifactService.GetBookmarks(paging, loggedOnUserId, RBookmarkType.Favorite, visibleItems); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(res.Result.PagingMeta)); return Ok(res.Result.Bookmarks); } /// /// add note for artifact /// /// /// [HttpPost] [Route("note")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserNoteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task AddUserNoteToArtifact([FromBody]PostUserNote note) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _artifactService.AddUserNoteToArtifact(note.EntityId, loggedOnUserId, note.NoteType, note.Contents, note.ReferenceNoteId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// add note for artifact item /// /// /// [HttpPost] [Route("note/item")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserNoteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task AddUserNoteToArtifactItem([FromBody]PostUserNote note) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _artifactService.AddUserNoteToArtifactItem(note.EntityId, loggedOnUserId, note.NoteType, note.Contents, note.ReferenceNoteId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// Edit User Notes /// /// a note can not be edited by a user other than its owner or another using having note:moderate permission /// /// only htmlContent is processed /// [HttpPut] [Route("note/{noteId}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserNoteViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task EditUserNote(Guid noteId, [FromBody]PostUserNote note) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult canModerate = await _userPermissionChecker.Check ( loggedOnUserId, new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value), RMuseumSecurableItem.NoteEntityShortName, RMuseumSecurableItem.ModerateOperationShortName ); if (!string.IsNullOrEmpty(canModerate.ExceptionString)) return BadRequest(canModerate.ExceptionString); RServiceResult res = await _artifactService.EditUserNote(noteId, canModerate.Result ? (Guid?)null : loggedOnUserId, note.Contents); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// delete user notes /// /// /// 1. a note can not be deleted by a user other than its owner or another using having note:moderate permission /// 2. all notes which have refernce to deleting note (sent in reply to it) would be deleted irrelevant of their ownership /// /// /// list of notes deleted [HttpDelete] [Route("note/{noteId}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(Guid[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task DeleteUserNote(Guid noteId) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult canModerate = await _userPermissionChecker.Check ( loggedOnUserId, new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value), RMuseumSecurableItem.NoteEntityShortName, RMuseumSecurableItem.ModerateOperationShortName ); if (!string.IsNullOrEmpty(canModerate.ExceptionString)) return BadRequest(canModerate.ExceptionString); RServiceResult res = await _artifactService.DeleteUserNote(noteId, canModerate.Result ? (Guid?)null : loggedOnUserId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// get private notes for artifact /// /// /// [HttpGet] [Route("note/private/{artifactId}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserNoteViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetArtifactUserNotes(Guid artifactId) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _artifactService.GetArtifactUserNotes(artifactId, loggedOnUserId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// get private notes for artifact /// /// /// [HttpGet] [Route("note/{artifactId}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserNoteViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetArtifactPublicNotes(Guid artifactId) { RServiceResult res = await _artifactService.GetArtifactPublicNotes(artifactId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// get private notes for artifact item /// /// /// [HttpGet] [Route("note/item/private/{itemId}")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserNoteViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetArtifactItemUserNotes(Guid itemId) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _artifactService.GetArtifactItemUserNotes(itemId, loggedOnUserId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// get public notes for artifact item /// /// /// [HttpGet] [Route("note/item/{itemId}")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserNoteViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetArtifactItemPublicNotes(Guid itemId) { RServiceResult res = await _artifactService.GetArtifactItemPublicNotes(itemId); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// user public notes /// /// [HttpGet] [Route("note/public")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserNoteViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetUserPublicNotes([FromQuery]PagingParameterModel paging) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult v = await _GetUserVisibleArtifactStatusSet ( loggedOnUserId, new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value) ); if (!string.IsNullOrEmpty(v.ExceptionString)) return BadRequest(v.ExceptionString); PublishStatus[] visibleItems = v.Result; RServiceResult<(PaginationMetadata PagingMeta, RUserNoteViewModel[] Notes)> res = await _artifactService.GetUserNotes(loggedOnUserId, paging, RNoteType.Public, visibleItems); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(res.Result.PagingMeta)); return Ok(res.Result.Notes); } /// /// user public notes /// /// [HttpGet] [Route("note/private")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserNoteViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetUserPrivateNotes([FromQuery]PagingParameterModel paging) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult v = await _GetUserVisibleArtifactStatusSet ( loggedOnUserId, new Guid(User.Claims.FirstOrDefault(c => c.Type == "SessionId").Value) ); if (!string.IsNullOrEmpty(v.ExceptionString)) return BadRequest(v.ExceptionString); PublishStatus[] visibleItems = v.Result; RServiceResult<(PaginationMetadata PagingMeta, RUserNoteViewModel[] Notes)> res = await _artifactService.GetUserNotes(loggedOnUserId, paging, RNoteType.Private, visibleItems); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(res.Result.PagingMeta)); return Ok(res.Result.Notes); } /// /// all users public notes /// /// [HttpGet] [Route("note/all")] [AllowAnonymous] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(RUserNoteViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetAllPublicNotes([FromQuery]PagingParameterModel paging) { RServiceResult<(PaginationMetadata PagingMeta, RUserNoteViewModel[] Notes)> res = await _artifactService.GetAllPublicNotes(paging); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); // Paging Header HttpContext.Response.Headers.Add("paging-headers", JsonConvert.SerializeObject(res.Result.PagingMeta)); return Ok(res.Result.Notes); } /// /// suggest ganjoor link /// /// /// [HttpPost] [Route("ganjoor")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorLinkViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task SuggestGanjoorLink([FromBody]LinkSuggestion link) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult suggestion = await _artifactService.SuggestGanjoorLink(loggedOnUserId, link); if (!string.IsNullOrEmpty(suggestion.ExceptionString)) return BadRequest(suggestion.ExceptionString); return Ok(suggestion.Result); } /// /// get suggested ganjoor links /// /// /// /// [HttpGet] [Route("ganjoor")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(GanjoorLinkViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetSuggestedLinks(ReviewResult status, bool notSynced) { RServiceResult res = await _artifactService.GetSuggestedLinks(status, notSynced); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// review suggested ganjoor link /// /// /// /// [HttpPut] [Route("ganjoor/review/{linkId}/{result}")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + RMuseumSecurableItem.ReviewGanjoorLinksOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task ReviewGanjoorLink(Guid linkId, ReviewResult result) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult suggestion = await _artifactService.ReviewSuggestedLink(linkId, loggedOnUserId, result); if (!string.IsNullOrEmpty(suggestion.ExceptionString)) return BadRequest(suggestion.ExceptionString); return Ok(); } /// /// mark suggested ganjoor link as synchronized /// /// /// [HttpPut] [Route("ganjoor/sync/{linkId}")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + RMuseumSecurableItem.ReviewGanjoorLinksOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task SynchronizeGanjoorLink(Guid linkId) { RServiceResult suggestion = await _artifactService.SynchronizeSuggestedLink(linkId); if (!string.IsNullOrEmpty(suggestion.ExceptionString)) return BadRequest(suggestion.ExceptionString); return Ok(); } /// ///toc / temporary one time api / to be removed /// /// [HttpPut] [Route("ganjoor/toc")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + RMuseumSecurableItem.ReviewGanjoorLinksOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task AddTOCForSuggestedLinks() { RServiceResult suggestion = await _artifactService.AddTOCForSuggestedLinks(); if (!string.IsNullOrEmpty(suggestion.ExceptionString)) return BadRequest(suggestion.ExceptionString); return Ok(suggestion.Result); } /// /// get suggested pinterest links /// /// /// /// [HttpGet] [Route("pinterest")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(PinterestLinkViewModel[]))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task GetSuggestedPinterestLinks(ReviewResult status, bool notSynced) { RServiceResult res = await _artifactService.GetSuggestedPinterestLinks(status, notSynced); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// suggest pinterest link for ganjoor /// /// /// [HttpPost] [Route("pinterest")] [Authorize] [ProducesResponseType((int)HttpStatusCode.OK, Type = typeof(PinterestLinkViewModel))] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task SuggestPinterestLink([FromBody]PinterestSuggestion suggestion) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult res = await _artifactService.SuggestPinterestLink(loggedOnUserId, suggestion); if (!string.IsNullOrEmpty(res.ExceptionString)) return BadRequest(res.ExceptionString); return Ok(res.Result); } /// /// review suggested ganjoor pinterest link /// /// /// /// /// /// /// [HttpPut] [Route("pinterest/review/{linkId}/{result}")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + RMuseumSecurableItem.ReviewGanjoorLinksOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task ReviewSuggestedPinterestLink(Guid linkId, string altText, ReviewResult result, string reviewDesc, string imageUrl) { Guid loggedOnUserId = new Guid(User.Claims.FirstOrDefault(c => c.Type == "UserId").Value); RServiceResult suggestion = await _artifactService.ReviewSuggestedPinterestLink(linkId, loggedOnUserId, altText, result, reviewDesc, imageUrl); if (!string.IsNullOrEmpty(suggestion.ExceptionString)) return BadRequest(suggestion.ExceptionString); return Ok(); } /// /// mark suggested pinterest ganjoor link as synchronized /// /// /// [HttpPut] [Route("pinterest/sync/{linkId}")] [Authorize(Policy = RMuseumSecurableItem.ArtifactEntityShortName + ":" + RMuseumSecurableItem.ReviewGanjoorLinksOperationShortName)] [ProducesResponseType((int)HttpStatusCode.OK)] [ProducesResponseType((int)HttpStatusCode.BadRequest, Type = typeof(string))] public async Task SynchronizeSuggestedPinterestLink(Guid linkId) { RServiceResult suggestion = await _artifactService.SynchronizeSuggestedPinterestLink(linkId); if (!string.IsNullOrEmpty(suggestion.ExceptionString)) return BadRequest(suggestion.ExceptionString); return Ok(); } /// /// constructor /// /// /// /// /// /// /// public ArtifactController(IArtifactService artifactService, IUserPermissionChecker userPermissionChecker, IMemoryCache memoryCache, ICaptchaService captchaService, IRNotificationService notificationService) { _artifactService = artifactService; _userPermissionChecker = userPermissionChecker; _memoryCache = memoryCache; _captchaService = captchaService; } /// /// Artifact Service /// protected readonly IArtifactService _artifactService; /// /// IUserPermissionChecker instance /// protected IUserPermissionChecker _userPermissionChecker; /// /// IMemoryCache /// protected readonly IMemoryCache _memoryCache; /// /// Captcha service /// protected readonly ICaptchaService _captchaService; } }