Skip to content

Commit

Permalink
chore: feature contents (#156)
Browse files Browse the repository at this point in the history
  • Loading branch information
Bendomey authored Jan 2, 2025
1 parent 42cd411 commit cb1f97e
Show file tree
Hide file tree
Showing 7 changed files with 257 additions and 78 deletions.
2 changes: 1 addition & 1 deletion services/main/Controllers/Collection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1054,7 +1054,7 @@ string name
StatusCodes.Status500InternalServerError,
Type = typeof(StatusCodeResult)
)]
public async Task<IActionResult> FeatureTag(string id)
public async Task<IActionResult> FeatureContent(string id)
{
try
{
Expand Down
107 changes: 106 additions & 1 deletion services/main/Controllers/Content.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class ContentController : ControllerBase
{
private readonly ILogger<ContentController> _logger;
private readonly EditContentService _editContentService;
private readonly CollectionContentService _collectionContentService;
private readonly ContentLikeService _contentLikeService;
private readonly IndexContent _indexContentService;
private readonly SearchContentService _searchContentService;
Expand All @@ -32,7 +33,8 @@ public ContentController(
EditContentService editContentService,
ContentTransformer contentTransformer,
ContentLikeTransformer contentLikeTransformer,
SearchTagService searchTagsService
SearchTagService searchTagsService,
CollectionContentService collectionContentService
)
{
_logger = logger;
Expand All @@ -43,6 +45,7 @@ SearchTagService searchTagsService
_contentTransformer = contentTransformer;
_contentLikeTransformer = contentLikeTransformer;
_searchTagsService = searchTagsService;
_collectionContentService = collectionContentService;
}

/// <summary>
Expand Down Expand Up @@ -836,5 +839,107 @@ public async Task<IActionResult> GetUserContentLikes(
}
}

/// <summary>
/// Feature content.
/// </summary>
/// <param name="id">id of content</param>
/// <response code="200">content Featured Successfully</response>
/// <response code="500">An unexpected error occured</response>
[Authorize(Policy = "Admin")]
[HttpPatch("{id}/feature")]
[ProducesResponseType(
StatusCodes.Status200OK,
Type = typeof(ApiEntityResponse<Models.CollectionContent>)
)]
[ProducesResponseType(
StatusCodes.Status500InternalServerError,
Type = typeof(StatusCodeResult)
)]
public async Task<IActionResult> FeatureContent(string id)
{
try
{
_logger.LogInformation("Featuring content: " + id);
var collectionContent = await _collectionContentService.FeatureCollection(id);

return new ObjectResult(new GetEntityResponse<Models.CollectionContent>(collectionContent, null).Result()) { StatusCode = StatusCodes.Status200OK };
}
catch (HttpRequestException e)
{
var statusCode = HttpStatusCode.BadRequest;
if (e.StatusCode != null)
{
statusCode = (HttpStatusCode)e.StatusCode;
}

return new ObjectResult(new GetEntityResponse<AnyType?>(null, e.Message).Result()) { StatusCode = (int)statusCode };
}
catch (Exception e)
{
this._logger.LogError($"Failed to feature content. Exception: {e}");
SentrySdk.ConfigureScope(scope =>
{
scope.SetTags(new Dictionary<string, string>
{
{"action", "Feature content"},
{"id", id}
});
SentrySdk.CaptureException(e);
});
return new StatusCodeResult(500);
}
}

/// <summary>
/// Feature content.
/// </summary>
/// <param name="id">id of content</param>
/// <response code="200">content UnFeatured Successfully</response>
/// <response code="500">An unexpected error occured</response>
[Authorize(Policy = "Admin")]
[HttpPatch("{id}/unfeature")]
[ProducesResponseType(
StatusCodes.Status200OK,
Type = typeof(ApiEntityResponse<bool>)
)]
[ProducesResponseType(
StatusCodes.Status500InternalServerError,
Type = typeof(StatusCodeResult)
)]
public async Task<IActionResult> UnFeatureContent(string id)
{
try
{
_logger.LogInformation("UnFeaturing content: " + id);
var collectionContent = await _collectionContentService.UnFeatureCollection(id);

return new ObjectResult(new GetEntityResponse<bool>(collectionContent, null).Result()) { StatusCode = StatusCodes.Status200OK };
}
catch (HttpRequestException e)
{
var statusCode = HttpStatusCode.BadRequest;
if (e.StatusCode != null)
{
statusCode = (HttpStatusCode)e.StatusCode;
}

return new ObjectResult(new GetEntityResponse<AnyType?>(null, e.Message).Result()) { StatusCode = (int)statusCode };
}
catch (Exception e)
{
this._logger.LogError($"Failed to unfeature collection. Exception: {e}");
SentrySdk.ConfigureScope(scope =>
{
scope.SetTags(new Dictionary<string, string>
{
{"action", "Unfeature collection"},
{"id", id}
});
SentrySdk.CaptureException(e);
});
return new StatusCodeResult(500);
}
}


}
9 changes: 6 additions & 3 deletions services/main/Controllers/Tag.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ namespace main.Controllers;
public class TagsController : ControllerBase
{
private readonly ILogger<TagsController> _logger;
private readonly CollectionContentService _collectionContentsService;
private readonly SaveTagsService _saveTagsService;
private readonly SearchTagService _searchTagsService;
private readonly TagTransformer _tagTransformer;
Expand All @@ -25,7 +26,8 @@ public class TagsController : ControllerBase

public TagsController(ILogger<TagsController> logger, SaveTagsService saveTagsService, SearchTagService searchTagService, TagTransformer tagTransformer,
ContentTransformer contentTransformer,
TagContentTransformer tagContentTransformer
TagContentTransformer tagContentTransformer,
CollectionContentService collectionContentsService
)
{
_logger = logger;
Expand All @@ -34,6 +36,7 @@ TagContentTransformer tagContentTransformer
_tagTransformer = tagTransformer;
_contentTransformer = contentTransformer;
_tagContentTransformer = tagContentTransformer;
_collectionContentsService = collectionContentsService;
}

/// <summary>
Expand Down Expand Up @@ -496,7 +499,7 @@ public async Task<IActionResult> FeatureTag(string id)
try
{
_logger.LogInformation("Featuring tag: " + id);
var collectionContent = await _saveTagsService.FeatureTag(id);
var collectionContent = await _collectionContentsService.FeatureTag(id);

return new ObjectResult(new GetEntityResponse<CollectionContent>(collectionContent, null).Result()) { StatusCode = StatusCodes.Status200OK };
}
Expand Down Expand Up @@ -547,7 +550,7 @@ public async Task<IActionResult> UnFeatureTag(string id)
try
{
_logger.LogInformation("UnFeaturing tag: " + id);
var collectionContent = await _saveTagsService.UnFeatureTag(id);
var collectionContent = await _collectionContentsService.UnFeatureTag(id);

return new ObjectResult(new GetEntityResponse<bool>(collectionContent, null).Result()) { StatusCode = StatusCodes.Status200OK };
}
Expand Down
1 change: 1 addition & 0 deletions services/main/DTOs/OutputContent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace main.DTOs;
public class OutputContent
{
public string Id { get; set; } = null!;
public required bool IsFeatured { get; set; }
public required string Title { get; set; }
public required string Slug { get; set; }
public string Type { get; set; } = "IMAGE";
Expand Down
143 changes: 142 additions & 1 deletion services/main/Domains/Collection/CollectionContentService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ namespace main.Domains;

public class CollectionContentService
{
private readonly SearchContentService _searchContentService;
private readonly CollectionService _collectionService;
private readonly SearchTagService _searchTagService;
private readonly ILogger<CollectionContentService> _logger;
private readonly IMongoCollection<Models.CollectionContent> _collectionContentCollection;
private readonly IMongoCollection<Models.Collection> _collectionCollection;
Expand All @@ -24,7 +26,9 @@ public CollectionContentService(
DatabaseSettings databaseConfig,
IOptions<AppConstants> appConstants,
CacheProvider cacheProvider,
CollectionService collectionService
CollectionService collectionService,
SearchTagService searchTagService,
SearchContentService searchContentService
)
{
_logger = logger;
Expand All @@ -35,6 +39,8 @@ CollectionService collectionService
_cacheProvider = cacheProvider;
_appConstantsConfiguration = appConstants.Value;
_collectionService = collectionService;
_searchTagService = searchTagService;
_searchContentService = searchContentService;

logger.LogDebug("Collection Content service initialized");
}
Expand Down Expand Up @@ -499,5 +505,140 @@ public async Task<bool> UnFeatureCollection(string collectionId)
}


public async Task<CollectionContent> FeatureTag(string tagId)
{
var tag = await _searchTagService.Get(tagId);
if (tag is null)
{
throw new HttpRequestException("TagNotFound");
}

if (tag.IsFeatured)
{
throw new HttpRequestException("TagAlreadyFeatured");
}

var featuredCollection = _collectionService.GetCollectionBySlug("featured_tags");

var newCollectionContent = SaveCollectionContent(new SaveCollectionContent
{
CollectionId = featuredCollection.Id,
Type = "TAG",
TagId = tag.Id,
});

var update = Builders<Models.Tag>.Update
.Set("is_featured", true)
.Set("updated_at", DateTime.UtcNow);
await _tagCollection.UpdateOneAsync(tag => tag.Id == tagId, update);

_ = _cacheProvider.EntityChanged(new[] {
$"{CacheProvider.CacheEntities["tags"]}.find*",
$"{CacheProvider.CacheEntities["tags"]}*{tag.Slug}*",
$"{CacheProvider.CacheEntities["tags"]}*{tag.Id}*",
});

return newCollectionContent;
}

public async Task<bool> UnFeatureTag(string tagId)
{
var tag = await _searchTagService.Get(tagId);
if (tag is null)
{
throw new HttpRequestException("TagNotFound");
}

if (!tag.IsFeatured)
{
throw new HttpRequestException("TagNotFeatured");
}

var featuredCollection = _collectionService.GetCollectionBySlug("featured_tags");

RemoveContentsFromCollection(new RemoveContentsFromCollectionInput
{
ContentIds = [tagId],
Id = featuredCollection.Id,
Type = "TAG",
});

var update = Builders<Models.Tag>.Update
.Set("is_featured", false)
.Set("updated_at", DateTime.UtcNow);
await _tagCollection.UpdateOneAsync(tag => tag.Id == tagId, update);

_ = _cacheProvider.EntityChanged(new[] {
$"{CacheProvider.CacheEntities["tags"]}.find*",
$"{CacheProvider.CacheEntities["tags"]}*{tag.Slug}*",
$"{CacheProvider.CacheEntities["tags"]}*{tag.Id}*",
});

return true;
}

public async Task<CollectionContent> FeatureContent(string contentId)
{
var content = await _searchContentService.GetContentById(contentId);

if (content.IsFeatured)
{
throw new HttpRequestException("ContentAlreadyFeatured");
}

var featuredCollection = _collectionService.GetCollectionBySlug("featured_contents");

var newCollectionContent = SaveCollectionContent(new SaveCollectionContent
{
CollectionId = featuredCollection.Id,
Type = "CONTENT",
ContentId = content.Id,
});

var update = Builders<Models.Content>.Update
.Set("is_featured", true)
.Set("updated_at", DateTime.UtcNow);
await _contentCollection.UpdateOneAsync(content => content.Id == contentId, update);

_ = _cacheProvider.EntityChanged(new[] {
$"{CacheProvider.CacheEntities["contents"]}.find*",
$"{CacheProvider.CacheEntities["contents"]}*{content.Slug}*",
$"{CacheProvider.CacheEntities["contents"]}*{content.Id}*",
});

return newCollectionContent;
}

public async Task<bool> UnFeatureContent(string contentId)
{
var content = await _searchContentService.GetContentById(contentId);

if (!content.IsFeatured)
{
throw new HttpRequestException("ContentNotFeatured");
}

var featuredCollection = _collectionService.GetCollectionBySlug("featured_contents");

RemoveContentsFromCollection(new RemoveContentsFromCollectionInput
{
ContentIds = [contentId],
Id = featuredCollection.Id,
Type = "CONTENT",
});

var update = Builders<Models.Content>.Update
.Set("is_featured", false)
.Set("updated_at", DateTime.UtcNow);
await _contentCollection.UpdateOneAsync(content => content.Id == contentId, update);

_ = _cacheProvider.EntityChanged(new[] {
$"{CacheProvider.CacheEntities["contents"]}.find*",
$"{CacheProvider.CacheEntities["contents"]}*{content.Slug}*",
$"{CacheProvider.CacheEntities["contents"]}*{content.Id}*",
});

return true;
}

}
Loading

0 comments on commit cb1f97e

Please sign in to comment.