mirror of https://github.com/abpframework/abp.git
committed by
GitHub
45 changed files with 3639 additions and 1250 deletions
File diff suppressed because it is too large
@ -0,0 +1,39 @@ |
|||
using System; |
|||
using Microsoft.EntityFrameworkCore.Migrations; |
|||
|
|||
namespace Volo.CmsKit.Migrations |
|||
{ |
|||
public partial class CmsRatings_Added : Migration |
|||
{ |
|||
protected override void Up(MigrationBuilder migrationBuilder) |
|||
{ |
|||
migrationBuilder.CreateTable( |
|||
name: "CmsRatings", |
|||
columns: table => new |
|||
{ |
|||
Id = table.Column<Guid>(nullable: false), |
|||
TenantId = table.Column<Guid>(nullable: true), |
|||
EntityType = table.Column<string>(maxLength: 64, nullable: false), |
|||
EntityId = table.Column<string>(maxLength: 64, nullable: false), |
|||
StarCount = table.Column<short>(nullable: false), |
|||
CreatorId = table.Column<Guid>(nullable: false), |
|||
CreationTime = table.Column<DateTime>(nullable: false) |
|||
}, |
|||
constraints: table => |
|||
{ |
|||
table.PrimaryKey("PK_CmsRatings", x => x.Id); |
|||
}); |
|||
|
|||
migrationBuilder.CreateIndex( |
|||
name: "IX_CmsRatings_TenantId_EntityType_EntityId", |
|||
table: "CmsRatings", |
|||
columns: new[] { "TenantId", "EntityType", "EntityId" }); |
|||
} |
|||
|
|||
protected override void Down(MigrationBuilder migrationBuilder) |
|||
{ |
|||
migrationBuilder.DropTable( |
|||
name: "CmsRatings"); |
|||
} |
|||
} |
|||
} |
|||
File diff suppressed because it is too large
@ -0,0 +1,37 @@ |
|||
.jq-stars { |
|||
display: inline-block; |
|||
} |
|||
|
|||
.jq-rating-label { |
|||
font-size: 22px; |
|||
display: inline-block; |
|||
position: relative; |
|||
vertical-align: top; |
|||
font-family: helvetica, arial, verdana; |
|||
} |
|||
|
|||
.jq-star { |
|||
width: 100px; |
|||
height: 100px; |
|||
display: inline-block; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.jq-star-svg { |
|||
width: 100%; |
|||
height: 100% ; |
|||
} |
|||
|
|||
.jq-star:hover .fs-star-svg polygon { |
|||
} |
|||
|
|||
.jq-star-svg polygon { |
|||
stroke: #000; |
|||
stroke-linejoin: round; |
|||
} |
|||
|
|||
/* un-used */ |
|||
.jq-shadow { |
|||
-webkit-filter: drop-shadow( -2px -2px 2px #888 ); |
|||
filter: drop-shadow( -2px -2px 2px #888 ); |
|||
} |
|||
@ -0,0 +1 @@ |
|||
!function(a){"use strict";var b="starRating",c=function(){},d={totalStars:5,useFullStars:!1,emptyColor:"lightgray",hoverColor:"orange",activeColor:"gold",useGradient:!0,readOnly:!1,disableAfterRate:!0,starGradient:{start:"#FEF7CD",end:"#FF9511"},strokeWidth:0,strokeColor:"black",initialRating:0,starSize:40,callback:c,onHover:c,onLeave:c},e=function(c,e){var f;this.element=c,this.$el=a(c),this.settings=a.extend({},d,e),f=this.$el.data("rating")||this.settings.initialRating,this._state={rating:(Math.round(2*f)/2).toFixed(1)},this._uid=Math.floor(999*Math.random()),e.starGradient||this.settings.useGradient||(this.settings.starGradient.start=this.settings.starGradient.end=this.settings.activeColor),this._defaults=d,this._name=b,this.init()},f={init:function(){this.renderMarkup(),this.addListeners(),this.initRating()},addListeners:function(){this.settings.readOnly||(this.$stars.on("mouseover",this.hoverRating.bind(this)),this.$stars.on("mouseout",this.restoreState.bind(this)),this.$stars.on("click",this.handleRating.bind(this)))},hoverRating:function(a){var b=this.getIndex(a);this.paintStars(b,"hovered"),this.settings.onHover(b+1,this._state.rating,this.$el)},handleRating:function(a){var b=this.getIndex(a),c=b+1;this.applyRating(c,this.$el),this.executeCallback(c,this.$el),this.settings.disableAfterRate&&this.$stars.off()},applyRating:function(a){var b=a-1;this.paintStars(b,"active"),this._state.rating=b+1},restoreState:function(a){var b=this.getIndex(a),c=this._state.rating||-1;this.paintStars(c-1,"active"),this.settings.onLeave(b+1,this._state.rating,this.$el)},getIndex:function(b){var c=a(b.currentTarget),d=c.width(),e=a(b.target).attr("data-side");e=e?e:this.getOffsetByPixel(b,c,d),e=this.settings.useFullStars?"right":e;var f=c.index()-("left"===e?.5:0);return f=.5>f&&b.offsetX<d/4?-1:f},getOffsetByPixel:function(a,b,c){var d=a.pageX-b.offset().left;return c/2>=d&&!this.settings.useFullStars?"left":"right"},initRating:function(){this.paintStars(this._state.rating-1,"active")},paintStars:function(b,c){var d,e,f,g;a.each(this.$stars,function(h,i){d=a(i).find('polygon[data-side="left"]'),e=a(i).find('polygon[data-side="right"]'),f=g=b>=h?c:"empty",f=h-b===.5?c:f,d.attr("class","svg-"+f+"-"+this._uid),e.attr("class","svg-"+g+"-"+this._uid)}.bind(this))},renderMarkup:function(){for(var a='<div class="jq-star" style="width:'+this.settings.starSize+"px; height:"+this.settings.starSize+'px;"><svg version="1.0" class="jq-star-svg" shape-rendering="geometricPrecision" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="305px" height="305px" viewBox="60 -62 309 309" style="enable-background:new 64 -59 305 305; stroke-width:'+this.settings.strokeWidth+'px;" xml:space="preserve"><style type="text/css">.svg-empty-'+this._uid+"{fill:url(#"+this._uid+"_SVGID_1_);}.svg-hovered-"+this._uid+"{fill:url(#"+this._uid+"_SVGID_2_);}.svg-active-"+this._uid+"{fill:url(#"+this._uid+"_SVGID_3_);}</style>"+this.getLinearGradient(this._uid+"_SVGID_1_",this.settings.emptyColor,this.settings.emptyColor)+this.getLinearGradient(this._uid+"_SVGID_2_",this.settings.hoverColor,this.settings.hoverColor)+this.getLinearGradient(this._uid+"_SVGID_3_",this.settings.starGradient.start,this.settings.starGradient.end)+'<polygon data-side="left" class="svg-empty-'+this._uid+'" points="281.1,129.8 364,55.7 255.5,46.8 214,-59 172.5,46.8 64,55.4 146.8,129.7 121.1,241 213.9,181.1 213.9,181 306.5,241 " style="stroke: '+this.settings.strokeColor+'"/><polygon data-side="right" class="svg-empty-'+this._uid+'" points="364,55.7 255.5,46.8 214,-59 213.9,181 306.5,241 281.1,129.8 " style="stroke-dasharray: 230 232 210 0; stroke: '+this.settings.strokeColor+'"/></svg></div>',b="",c=0;c<this.settings.totalStars;c++)b+=a;this.$el.append(b),this.$stars=this.$el.find(".jq-star")},getLinearGradient:function(a,b,c){return'<linearGradient id="'+a+'" gradientUnits="userSpaceOnUse" x1="121.1501" y1="-70.35" x2="121.15" y2="125.0045"><stop offset="0" style="stop-color:'+b+'"/><stop offset="1" style="stop-color:'+c+'"/> </linearGradient>'},executeCallback:function(a,b){var c=this.settings.callback;c(a,b)}},g={unload:function(){var c="plugin_"+b,d=a(this),e=d.data(c).$stars;e.off(),d.removeData(c).remove()},setRating:function(c,d){var e="plugin_"+b,f=a(this),g=f.data(e);c>g.settings.totalStars||0>c||(d&&(c=Math.round(c)),g.applyRating(c))},getRating:function(){var c="plugin_"+b,d=a(this),e=d.data(c);return e._state.rating}};a.extend(e.prototype,f),a.fn[b]=function(c){if(!a.isPlainObject(c)){if(g.hasOwnProperty(c))return g[c].apply(this,Array.prototype.slice.call(arguments,1));a.error("Method "+c+" does not exist on "+b+".js")}return this.each(function(){a.data(this,"plugin_"+b)||a.data(this,"plugin_"+b,new e(this,c))})}}(jQuery,window,document); |
|||
@ -0,0 +1,18 @@ |
|||
using JetBrains.Annotations; |
|||
using Volo.Abp.GlobalFeatures; |
|||
|
|||
namespace Volo.CmsKit.GlobalFeatures |
|||
{ |
|||
[GlobalFeatureName(Name)] |
|||
public class RatingsFeature : GlobalFeature |
|||
{ |
|||
public const string Name = "CmsKit.Ratings"; |
|||
|
|||
internal RatingsFeature( |
|||
[NotNull] GlobalCmsKitFeatures cmsKit |
|||
) : base(cmsKit) |
|||
{ |
|||
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
using Volo.CmsKit.Entities; |
|||
|
|||
namespace Volo.CmsKit.Ratings |
|||
{ |
|||
public static class RatingConsts |
|||
{ |
|||
public static int MaxEntityTypeLength { get; set; } = CmsEntityConsts.MaxEntityTypeLength; |
|||
|
|||
public static int MaxEntityIdLength { get; set; } = CmsEntityConsts.MaxEntityIdLength; |
|||
|
|||
public static int MaxStarCount { get; set; } = 5; |
|||
|
|||
public static int MinStarCount { get; set; } = 1; |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using JetBrains.Annotations; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace Volo.CmsKit.Ratings |
|||
{ |
|||
public interface IRatingRepository : IBasicRepository<Rating, Guid> |
|||
{ |
|||
Task<Rating> GetCurrentUserRatingAsync( |
|||
[NotNull] string entityType, |
|||
[NotNull] string entityId, |
|||
Guid userId, |
|||
CancellationToken cancellationToken = default |
|||
); |
|||
|
|||
Task<List<RatingWithStarCountQueryResultItem>> GetGroupedStarCountsAsync( |
|||
[NotNull] string entityType, |
|||
[NotNull] string entityId, |
|||
CancellationToken cancellationToken = default |
|||
); |
|||
} |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
using System; |
|||
using JetBrains.Annotations; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Auditing; |
|||
using Volo.Abp.Domain.Entities; |
|||
|
|||
namespace Volo.CmsKit.Ratings |
|||
{ |
|||
public class Rating : BasicAggregateRoot<Guid>, IHasCreationTime, IMustHaveCreator |
|||
{ |
|||
public virtual Guid? TenantId { get; protected set; } |
|||
|
|||
public virtual string EntityType { get; protected set; } |
|||
|
|||
public virtual string EntityId { get; protected set; } |
|||
|
|||
public virtual short StarCount { get; protected set; } |
|||
|
|||
public virtual Guid CreatorId { get; set; } |
|||
|
|||
public virtual DateTime CreationTime { get; set; } |
|||
|
|||
protected Rating() |
|||
{ |
|||
|
|||
} |
|||
|
|||
public Rating( |
|||
Guid id, |
|||
[NotNull] string entityType, |
|||
[NotNull] string entityId, |
|||
short starCount, |
|||
Guid creatorId, |
|||
Guid? tenantId = null |
|||
) |
|||
: base(id) |
|||
{ |
|||
EntityType = Check.NotNullOrWhiteSpace(entityType, nameof(entityType), RatingConsts.MaxEntityTypeLength); |
|||
EntityId = Check.NotNullOrWhiteSpace(entityId, nameof(entityId), RatingConsts.MaxEntityIdLength); |
|||
SetStarCount(starCount); |
|||
CreatorId = creatorId; |
|||
TenantId = tenantId; |
|||
} |
|||
|
|||
public virtual void SetStarCount(short starCount) |
|||
{ |
|||
if(starCount <= RatingConsts.MaxStarCount && starCount >= RatingConsts.MinStarCount) |
|||
{ |
|||
StarCount = starCount; |
|||
} |
|||
else |
|||
{ |
|||
throw new ArgumentOutOfRangeException($"Choosen star must between {RatingConsts.MinStarCount} and {RatingConsts.MaxStarCount}"); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
namespace Volo.CmsKit.Ratings |
|||
{ |
|||
public class RatingWithStarCountQueryResultItem |
|||
{ |
|||
public short StarCount { get; set; } |
|||
|
|||
public int Count { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Linq.Dynamic.Core; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
using Volo.CmsKit.EntityFrameworkCore; |
|||
|
|||
namespace Volo.CmsKit.Ratings |
|||
{ |
|||
public class EfCoreRatingRepository : EfCoreRepository<ICmsKitDbContext, Rating, Guid>, IRatingRepository |
|||
{ |
|||
public EfCoreRatingRepository(IDbContextProvider<ICmsKitDbContext> dbContextProvider) : base(dbContextProvider) |
|||
{ |
|||
} |
|||
|
|||
public async Task<Rating> GetCurrentUserRatingAsync(string entityType, string entityId, Guid userId, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); |
|||
Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); |
|||
|
|||
var rating = await DbSet.FirstOrDefaultAsync( |
|||
r => r.EntityType == entityType && r.EntityId == entityId && r.CreatorId == userId, |
|||
GetCancellationToken(cancellationToken)); |
|||
|
|||
return rating; |
|||
} |
|||
|
|||
public async Task<List<RatingWithStarCountQueryResultItem>> GetGroupedStarCountsAsync(string entityType, |
|||
string entityId, CancellationToken cancellationToken = default) |
|||
{ |
|||
Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); |
|||
Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); |
|||
|
|||
var query = ( |
|||
from rating in DbSet |
|||
where rating.EntityType == entityType && rating.EntityId == entityId |
|||
group rating by rating.StarCount |
|||
into g |
|||
select new RatingWithStarCountQueryResultItem |
|||
{ |
|||
StarCount = g.Key, |
|||
Count = g.Count() |
|||
} |
|||
).OrderByDescending(r => r.StarCount); |
|||
|
|||
var ratings = await query.ToListAsync(GetCancellationToken(cancellationToken)); |
|||
|
|||
return ratings; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading; |
|||
using System.Threading.Tasks; |
|||
using MongoDB.Driver; |
|||
using MongoDB.Driver.Linq; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Domain.Repositories.MongoDB; |
|||
using Volo.Abp.MongoDB; |
|||
using Volo.CmsKit.Ratings; |
|||
|
|||
namespace Volo.CmsKit.MongoDB.Ratings |
|||
{ |
|||
public class MongoRatingRepository : MongoDbRepository<ICmsKitMongoDbContext, Rating, Guid>, IRatingRepository |
|||
{ |
|||
public MongoRatingRepository(IMongoDbContextProvider<ICmsKitMongoDbContext> dbContextProvider) : base( |
|||
dbContextProvider) |
|||
{ |
|||
} |
|||
|
|||
public async Task<Rating> GetCurrentUserRatingAsync(string entityType, string entityId, Guid userId, |
|||
CancellationToken cancellationToken = default) |
|||
{ |
|||
Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); |
|||
Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); |
|||
|
|||
var rating = await GetMongoQueryable() |
|||
.FirstOrDefaultAsync(r => r.EntityType == entityType && r.EntityId == entityId && r.CreatorId == userId, |
|||
GetCancellationToken(cancellationToken)); |
|||
|
|||
return rating; |
|||
} |
|||
|
|||
public async Task<List<RatingWithStarCountQueryResultItem>> GetGroupedStarCountsAsync(string entityType, |
|||
string entityId, CancellationToken cancellationToken = default) |
|||
{ |
|||
Check.NotNullOrWhiteSpace(entityType, nameof(entityType)); |
|||
Check.NotNullOrWhiteSpace(entityId, nameof(entityId)); |
|||
|
|||
var query = ( |
|||
from rating in GetMongoQueryable() |
|||
where rating.EntityType == entityType && rating.EntityId == entityId |
|||
group rating by rating.StarCount |
|||
into g |
|||
select new RatingWithStarCountQueryResultItem |
|||
{ |
|||
StarCount = g.Key, |
|||
Count = g.Count() |
|||
} |
|||
).OrderByDescending(r => r.StarCount); |
|||
|
|||
var ratings = await query.ToListAsync(GetCancellationToken(cancellationToken)); |
|||
|
|||
return ratings; |
|||
} |
|||
} |
|||
} |
|||
@ -1,15 +1,15 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\..\common.props" /> |
|||
<Import Project="..\..\..\..\configureawait.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Volo.CmsKit.Common.Application.Contracts\Volo.CmsKit.Common.Application.Contracts.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\..\common.props" /> |
|||
<Import Project="..\..\..\..\configureawait.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Volo.CmsKit.Common.Application.Contracts\Volo.CmsKit.Common.Application.Contracts.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
|
|||
@ -0,0 +1,13 @@ |
|||
using System.ComponentModel.DataAnnotations; |
|||
using Volo.Abp.Validation; |
|||
using Volo.CmsKit.Ratings; |
|||
|
|||
namespace Volo.CmsKit.Public.Ratings |
|||
{ |
|||
public class CreateUpdateRatingInput |
|||
{ |
|||
[Required] |
|||
[DynamicRange(typeof(RatingConsts), typeof(int), nameof(RatingConsts.MinStarCount), nameof(RatingConsts.MaxStarCount))] |
|||
public short StarCount { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace Volo.CmsKit.Public.Ratings |
|||
{ |
|||
public interface IRatingPublicAppService : IApplicationService |
|||
{ |
|||
Task<RatingDto> CreateAsync(string entityType, string entityId, CreateUpdateRatingInput input); |
|||
|
|||
Task DeleteAsync(string entityType, string entityId); |
|||
|
|||
Task<RatingDto> GetCurrentUserRatingAsync(string entityType, string entityId); |
|||
|
|||
Task<List<RatingWithStarCountDto>> GetGroupedStarCountsAsync(string entityType, string entityId); |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
using System; |
|||
|
|||
namespace Volo.CmsKit.Public.Ratings |
|||
{ |
|||
public class RatingDto |
|||
{ |
|||
public Guid Id { get; set; } |
|||
|
|||
public string EntityType { get; set; } |
|||
|
|||
public string EntityId { get; set; } |
|||
|
|||
public short StarCount { get; set; } |
|||
|
|||
public Guid CreatorId { get; set; } |
|||
|
|||
public DateTime CreationTime { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
namespace Volo.CmsKit.Public.Ratings |
|||
{ |
|||
public class RatingWithStarCountDto |
|||
{ |
|||
public short StarCount { get; set; } |
|||
|
|||
public int Count { get; set; } |
|||
|
|||
public bool IsSelectedByCurrentUser { get; set; } |
|||
} |
|||
} |
|||
@ -1,16 +1,16 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\..\common.props" /> |
|||
<Import Project="..\..\..\..\configureawait.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Volo.CmsKit.Common.Application\Volo.CmsKit.Common.Application.csproj" /> |
|||
<ProjectReference Include="..\Volo.CmsKit.Public.Application.Contracts\Volo.CmsKit.Public.Application.Contracts.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\..\common.props" /> |
|||
<Import Project="..\..\..\..\configureawait.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netstandard2.0</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Volo.CmsKit.Common.Application\Volo.CmsKit.Common.Application.csproj" /> |
|||
<ProjectReference Include="..\Volo.CmsKit.Public.Application.Contracts\Volo.CmsKit.Public.Application.Contracts.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
|
|||
@ -0,0 +1,104 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Authorization; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Application.Services; |
|||
using Volo.Abp.Authorization; |
|||
using Volo.Abp.Users; |
|||
using Volo.CmsKit.Ratings; |
|||
using Volo.CmsKit.Users; |
|||
|
|||
namespace Volo.CmsKit.Public.Ratings |
|||
{ |
|||
public class RatingPublicAppService : ApplicationService, IRatingPublicAppService |
|||
{ |
|||
protected IRatingRepository RatingRepository { get; } |
|||
public ICmsUserLookupService CmsUserLookupService { get; } |
|||
|
|||
public RatingPublicAppService(IRatingRepository ratingRepository, ICmsUserLookupService cmsUserLookupService) |
|||
{ |
|||
RatingRepository = ratingRepository; |
|||
CmsUserLookupService = cmsUserLookupService; |
|||
} |
|||
|
|||
[Authorize] |
|||
public virtual async Task<RatingDto> CreateAsync(string entityType, string entityId, |
|||
CreateUpdateRatingInput input) |
|||
{ |
|||
var userId = CurrentUser.GetId(); |
|||
var user = await CmsUserLookupService.GetByIdAsync(userId); |
|||
|
|||
var currentUserRating = await RatingRepository.GetCurrentUserRatingAsync(entityType, entityId, userId); |
|||
|
|||
if (currentUserRating != null) |
|||
{ |
|||
currentUserRating.SetStarCount(input.StarCount); |
|||
var updatedRating = await RatingRepository.UpdateAsync(currentUserRating); |
|||
|
|||
return ObjectMapper.Map<Rating, RatingDto>(updatedRating); |
|||
} |
|||
|
|||
var rating = await RatingRepository.InsertAsync( |
|||
new Rating( |
|||
GuidGenerator.Create(), |
|||
entityType, |
|||
entityId, |
|||
input.StarCount, |
|||
user.Id, |
|||
CurrentTenant.Id |
|||
) |
|||
); |
|||
|
|||
return ObjectMapper.Map<Rating, RatingDto>(rating); |
|||
} |
|||
|
|||
[Authorize] |
|||
public virtual async Task DeleteAsync(string entityType, string entityId) |
|||
{ |
|||
var rating = await RatingRepository.GetCurrentUserRatingAsync(entityType, entityId, CurrentUser.GetId()); |
|||
|
|||
if (rating.CreatorId != CurrentUser.GetId()) |
|||
{ |
|||
throw new AbpAuthorizationException(); |
|||
} |
|||
|
|||
await RatingRepository.DeleteAsync(rating.Id); |
|||
} |
|||
|
|||
[Authorize] |
|||
public virtual async Task<RatingDto> GetCurrentUserRatingAsync(string entityType, string entityId) |
|||
{ |
|||
var currentUserId = CurrentUser.GetId(); |
|||
|
|||
var rating = await RatingRepository.GetCurrentUserRatingAsync(entityType, entityId, currentUserId); |
|||
|
|||
return ObjectMapper.Map<Rating, RatingDto>(rating); |
|||
} |
|||
|
|||
public virtual async Task<List<RatingWithStarCountDto>> GetGroupedStarCountsAsync(string entityType, |
|||
string entityId) |
|||
{ |
|||
var ratings = await RatingRepository.GetGroupedStarCountsAsync(entityType, entityId); |
|||
|
|||
var userRatingOrNull = CurrentUser.IsAuthenticated |
|||
? await RatingRepository.GetCurrentUserRatingAsync(entityType, entityId, CurrentUser.GetId()) |
|||
: null; |
|||
|
|||
var ratingWithStarCountDto = new List<RatingWithStarCountDto>(); |
|||
|
|||
foreach (var rating in ratings) |
|||
{ |
|||
ratingWithStarCountDto.Add( |
|||
new RatingWithStarCountDto |
|||
{ |
|||
StarCount = rating.StarCount, |
|||
Count = rating.Count, |
|||
IsSelectedByCurrentUser = userRatingOrNull != null && userRatingOrNull.StarCount == rating.StarCount |
|||
}); |
|||
} |
|||
|
|||
return ratingWithStarCountDto; |
|||
} |
|||
} |
|||
} |
|||
@ -1,16 +1,16 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\..\common.props" /> |
|||
<Import Project="..\..\..\..\configureawait.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netcoreapp3.1</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Volo.CmsKit.Common.HttpApi\Volo.CmsKit.Common.HttpApi.csproj" /> |
|||
<ProjectReference Include="..\Volo.CmsKit.Public.Application.Contracts\Volo.CmsKit.Public.Application.Contracts.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
|
|||
<Import Project="..\..\..\..\common.props" /> |
|||
<Import Project="..\..\..\..\configureawait.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>netcoreapp3.1</TargetFramework> |
|||
<RootNamespace /> |
|||
</PropertyGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\Volo.CmsKit.Common.HttpApi\Volo.CmsKit.Common.HttpApi.csproj" /> |
|||
<ProjectReference Include="..\Volo.CmsKit.Public.Application.Contracts\Volo.CmsKit.Public.Application.Contracts.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
|
|||
@ -0,0 +1,51 @@ |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp; |
|||
using Volo.Abp.GlobalFeatures; |
|||
using Volo.CmsKit.GlobalFeatures; |
|||
|
|||
namespace Volo.CmsKit.Public.Ratings |
|||
{ |
|||
[RequiresGlobalFeature(typeof(RatingsFeature))] |
|||
[RemoteService(Name = CmsKitPublicRemoteServiceConsts.RemoteServiceName)] |
|||
[Area("cms-kit")] |
|||
[Route("api/cms-kit-public/ratings")] |
|||
public class RatingPublicController : CmsKitPublicControllerBase, IRatingPublicAppService |
|||
{ |
|||
protected IRatingPublicAppService RatingPublicAppService { get; } |
|||
|
|||
public RatingPublicController(IRatingPublicAppService ratingPublicAppService) |
|||
{ |
|||
RatingPublicAppService = ratingPublicAppService; |
|||
} |
|||
|
|||
[HttpPut] |
|||
[Route("{entityType}/{entityId}")] |
|||
public virtual Task<RatingDto> CreateAsync(string entityType, string entityId, CreateUpdateRatingInput input) |
|||
{ |
|||
return RatingPublicAppService.CreateAsync(entityType, entityId, input); |
|||
} |
|||
|
|||
[HttpDelete] |
|||
[Route("{entityType}/{entityId}")] |
|||
public virtual Task DeleteAsync(string entityType, string entityId) |
|||
{ |
|||
return RatingPublicAppService.DeleteAsync(entityType, entityId); |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("{entityType}/{entityId}")] |
|||
public virtual Task<RatingDto> GetCurrentUserRatingAsync(string entityType, string entityId) |
|||
{ |
|||
return RatingPublicAppService.GetCurrentUserRatingAsync(entityType, entityId); |
|||
} |
|||
|
|||
[HttpGet] |
|||
[Route("{entityType}/{entityId}")] |
|||
public virtual Task<List<RatingWithStarCountDto>> GetGroupedStarCountsAsync(string entityType, string entityId) |
|||
{ |
|||
return RatingPublicAppService.GetGroupedStarCountsAsync(entityType, entityId); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
@using Microsoft.AspNetCore.Mvc.Localization |
|||
@using Volo.Abp.Users |
|||
@using Volo.CmsKit.Localization |
|||
@inject ICurrentUser CurrentUser |
|||
@model Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Rating.RatingViewModel |
|||
@inject IHtmlLocalizer<CmsKitResource> L |
|||
|
|||
<div class="cms-rating-area container" data-entity-type="@Model.EntityType" data-entity-id="@Model.EntityId" id="cms-rating_{@Model.EntityType}_{@Model.EntityId}"> |
|||
@if (CurrentUser.IsAuthenticated) |
|||
{ |
|||
<div class="m-auto"> |
|||
<span class="my-rating-5" data-rating="@(Model.CurrentRating ?? 0)" data-authenticated="@(Model.CurrentRating != null)"></span> |
|||
<span class="live-rating">@(Model.CurrentRating != null ? Model.CurrentRating + " | " : 0 + "")</span> |
|||
@if (Model.CurrentRating != null) |
|||
{ |
|||
<a href="#" class="rating-undo-link m-auto"> |
|||
<i class="fa fa-undo"></i> @L["Undo"] |
|||
</a> |
|||
} |
|||
</div> |
|||
if (Model.Ratings != null) |
|||
{ |
|||
<div class="row text-center col-6 mt-3"> |
|||
@foreach (var rating in Model.Ratings) |
|||
{ |
|||
<div class="side col-2"> |
|||
<div>@rating.StarCount @L["Star"]</div> |
|||
</div> |
|||
<div class="middle col-8"> |
|||
<div class="bar-container"> |
|||
<div class="bar bar-@rating.StarCount" style="width: @(rating.Count * 100 / Model.TotalRating)%"></div> |
|||
</div> |
|||
</div> |
|||
<div class="side col-2"> |
|||
<div>@rating.Count</div> |
|||
</div> |
|||
} |
|||
</div> |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
<span class="my-rating-5" data-authenticated="True" data-toggle="popover" data-placement="right" data-html="true" data-content="<div class='text-center'><a href='@Model.LoginUrl' class='btn btn-primary btn-block'>@L["LoginToRate"]</a></div>"></span> |
|||
<span class="rating-login"></span> |
|||
} |
|||
</div> |
|||
@ -0,0 +1,16 @@ |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Packages.StarRatingSvg; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Rating |
|||
{ |
|||
[DependsOn(typeof(StarRatingSvgScriptContributor))] |
|||
public class RatingScriptBundleContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files.AddIfNotContains("/Pages/CmsKit/Shared/Components/Rating/default.js"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
using System.Collections.Generic; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Packages.StarRatingSvg; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Rating |
|||
{ |
|||
[DependsOn(typeof(StarRatingSvgStyleContributor))] |
|||
public class RatingStyleBundleContributor : BundleContributor |
|||
{ |
|||
public override void ConfigureBundle(BundleConfigurationContext context) |
|||
{ |
|||
context.Files.AddIfNotContains("/Pages/CmsKit/Shared/Components/Rating/default.css"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.Abp.AspNetCore.Mvc; |
|||
using Volo.Abp.AspNetCore.Mvc.UI; |
|||
using Volo.Abp.AspNetCore.Mvc.UI.Widgets; |
|||
using Volo.Abp.Users; |
|||
using Volo.CmsKit.Public.Ratings; |
|||
|
|||
namespace Volo.CmsKit.Public.Web.Pages.CmsKit.Shared.Components.Rating |
|||
{ |
|||
[ViewComponent(Name = "CmsRating")] |
|||
[Widget( |
|||
StyleTypes = new[] {typeof(RatingStyleBundleContributor)}, |
|||
ScriptTypes = new[] {typeof(RatingScriptBundleContributor)}, |
|||
RefreshUrl = "/CmsKitPublicWidgets/Rating" |
|||
)] |
|||
public class RatingViewComponent : AbpViewComponent |
|||
{ |
|||
public IRatingPublicAppService RatingPublicAppService { get; } |
|||
public AbpMvcUiOptions AbpMvcUiOptions { get; } |
|||
public ICurrentUser CurrentUser { get; } |
|||
|
|||
public RatingViewComponent(IRatingPublicAppService ratingPublicAppService, IOptions<AbpMvcUiOptions> options, ICurrentUser currentUser) |
|||
{ |
|||
RatingPublicAppService = ratingPublicAppService; |
|||
AbpMvcUiOptions = options.Value; |
|||
CurrentUser = currentUser; |
|||
} |
|||
|
|||
public virtual async Task<IViewComponentResult> InvokeAsync(string entityType, string entityId) |
|||
{ |
|||
var ratings = await RatingPublicAppService.GetGroupedStarCountsAsync(entityType, entityId); |
|||
var totalRating = ratings.Sum(x => x.Count); |
|||
|
|||
short? currentUserRating = null; |
|||
if (CurrentUser.IsAuthenticated) |
|||
{ |
|||
currentUserRating = ratings.Find(x => x.IsSelectedByCurrentUser)?.StarCount; |
|||
} |
|||
|
|||
var loginUrl = |
|||
$"{AbpMvcUiOptions.LoginUrl}?returnUrl={HttpContext.Request.Path.ToString()}&returnUrlHash=#cms-rating_{entityType}_{entityId}"; |
|||
|
|||
var viewModel = new RatingViewModel |
|||
{ |
|||
EntityId = entityId, |
|||
EntityType = entityType, |
|||
LoginUrl = loginUrl, |
|||
Ratings = ratings, |
|||
CurrentRating = currentUserRating, |
|||
TotalRating = totalRating |
|||
}; |
|||
|
|||
return View("~/Pages/CmsKit/Shared/Components/Rating/Default.cshtml", viewModel); |
|||
} |
|||
} |
|||
|
|||
public class RatingViewModel |
|||
{ |
|||
public string EntityType { get; set; } |
|||
|
|||
public string EntityId { get; set; } |
|||
|
|||
public string LoginUrl { get; set; } |
|||
|
|||
public List<RatingWithStarCountDto> Ratings { get; set; } |
|||
|
|||
public short? CurrentRating { get; set; } |
|||
|
|||
public int TotalRating { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
.side { |
|||
width: 15%; |
|||
margin-top:10px; |
|||
} |
|||
|
|||
.middle { |
|||
float: left; |
|||
width: 70%; |
|||
margin-top:10px; |
|||
padding-top: 4px; |
|||
} |
|||
|
|||
.row:after { |
|||
content: ""; |
|||
display: table; |
|||
clear: both; |
|||
} |
|||
|
|||
.bar-container { |
|||
width: 100%; |
|||
background-color: #f1f1f1; |
|||
text-align: center; |
|||
color: white; |
|||
} |
|||
|
|||
.bar { |
|||
height: 18px; |
|||
} |
|||
|
|||
/* Individual bars */ |
|||
.bar-5 { background-color: #173F5F; } |
|||
.bar-4 { background-color: #20639B; } |
|||
.bar-3 { background-color: #3CAEA3; } |
|||
.bar-2 { background-color: #F6D55C; } |
|||
.bar-1 { background-color: #ED553B; } |
|||
|
|||
@media (max-width: 400px) { |
|||
.side, .middle { |
|||
width: 100%; |
|||
} |
|||
.right { |
|||
display: none; |
|||
} |
|||
} |
|||
@ -0,0 +1,87 @@ |
|||
(function () { |
|||
var l = abp.localization.getResource("CmsKit"); |
|||
|
|||
$(document).ready(function () { |
|||
abp.widgets.CmsRating = function ($widget) { |
|||
var widgetManager = $widget.data("abp-widget-manager"); |
|||
var $ratingArea = $widget.find(".cms-rating-area"); |
|||
|
|||
function getFilters() { |
|||
return { |
|||
entityType: $ratingArea.attr("data-entity-type"), |
|||
entityId: $ratingArea.attr("data-entity-id") |
|||
}; |
|||
} |
|||
|
|||
function registerCreateOfNewRating() { |
|||
$widget.find(".my-rating-5").each(function () { |
|||
var authenticated = $(this).attr("data-authenticated"); |
|||
|
|||
$(this).starRating({ |
|||
initialRating: 0, |
|||
disableAfterRate: true, |
|||
useFullStars: true, |
|||
readOnly: authenticated === "True", |
|||
onHover: function (currentIndex, currentRating, $el) { |
|||
$widget.find(".live-rating").text(currentIndex); |
|||
}, |
|||
onLeave: function (currentIndex, currentRating, $el) { |
|||
$widget.find(".live-rating").text(currentRating); |
|||
}, |
|||
callback: function (currentRating, $el) { |
|||
volo.cmsKit.public.ratings.ratingPublic.create( |
|||
$ratingArea.attr("data-entity-type"), |
|||
$ratingArea.attr("data-entity-id"), |
|||
{ |
|||
starCount: parseInt(currentRating) |
|||
} |
|||
).then(function () { |
|||
widgetManager.refresh($widget); |
|||
}) |
|||
} |
|||
}); |
|||
} |
|||
); |
|||
} |
|||
|
|||
function registerUndoLink() { |
|||
$widget.find(".rating-undo-link").each(function () { |
|||
$(this).on('click', '', function (e) { |
|||
e.preventDefault(); |
|||
|
|||
abp.message.confirm(l("RatingUndoMessage"), function (ok) { |
|||
if (ok) { |
|||
volo.cmsKit.public.ratings.ratingPublic.delete( |
|||
$ratingArea.attr("data-entity-type"), |
|||
$ratingArea.attr("data-entity-id") |
|||
).then(function () { |
|||
widgetManager.refresh($widget); |
|||
}); |
|||
} |
|||
}) |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
function init() { |
|||
registerCreateOfNewRating(); |
|||
registerUndoLink(); |
|||
} |
|||
|
|||
return { |
|||
init: init, |
|||
getFilters: getFilters |
|||
} |
|||
}; |
|||
|
|||
$('.abp-widget-wrapper[data-widget-name="CmsRating"]') |
|||
.each(function () { |
|||
var widgetManager = new abp.WidgetManager({ |
|||
wrapper: $(this), |
|||
}); |
|||
|
|||
widgetManager.init($(this)); |
|||
}); |
|||
}); |
|||
}) |
|||
(jQuery); |
|||
@ -0,0 +1,137 @@ |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using NSubstitute; |
|||
using Shouldly; |
|||
using Volo.Abp.Users; |
|||
using Volo.CmsKit.Public.Ratings; |
|||
using Xunit; |
|||
|
|||
namespace Volo.CmsKit.Ratings |
|||
{ |
|||
public class RatingPublicAppService_Tests : CmsKitApplicationTestBase |
|||
{ |
|||
private readonly IRatingPublicAppService _ratingAppService; |
|||
private ICurrentUser _currentUser; |
|||
private readonly CmsKitTestData _cmsKitTestData; |
|||
|
|||
public RatingPublicAppService_Tests() |
|||
{ |
|||
_ratingAppService = GetRequiredService<IRatingPublicAppService>(); |
|||
_cmsKitTestData = GetRequiredService<CmsKitTestData>(); |
|||
} |
|||
|
|||
protected override void AfterAddApplication(IServiceCollection services) |
|||
{ |
|||
_currentUser = Substitute.For<ICurrentUser>(); |
|||
services.AddSingleton(_currentUser); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task CreateAsync() |
|||
{ |
|||
_currentUser.Id.Returns(_cmsKitTestData.User1Id); |
|||
|
|||
var newRating = await _ratingAppService.CreateAsync( |
|||
_cmsKitTestData.EntityType1, |
|||
_cmsKitTestData.EntityId2, |
|||
new CreateUpdateRatingInput |
|||
{ |
|||
StarCount = 4 |
|||
}); |
|||
|
|||
UsingDbContext(context => |
|||
{ |
|||
var ratings = context.Set<Rating>().Where(x => |
|||
x.EntityId == _cmsKitTestData.EntityId1 && x.EntityType == _cmsKitTestData.EntityType1).ToList(); |
|||
|
|||
ratings |
|||
.Any(c => c.Id == newRating.Id && c.CreatorId == newRating.CreatorId && |
|||
c.StarCount == newRating.StarCount) |
|||
.ShouldBeTrue(); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task CreateAsync_Should_Update_If_Rating_Is_Exist() |
|||
{ |
|||
_currentUser.Id.Returns(_cmsKitTestData.User1Id); |
|||
|
|||
var entity = |
|||
await _ratingAppService.GetCurrentUserRatingAsync(_cmsKitTestData.EntityType1, |
|||
_cmsKitTestData.EntityId1); |
|||
|
|||
var updatedEntity = await _ratingAppService.CreateAsync( |
|||
_cmsKitTestData.EntityType1, |
|||
_cmsKitTestData.EntityId1, |
|||
new CreateUpdateRatingInput |
|||
{ |
|||
StarCount = 5 |
|||
}); |
|||
|
|||
entity.Id.ShouldBe(updatedEntity.Id); |
|||
entity.EntityId.ShouldBe(updatedEntity.EntityId); |
|||
entity.EntityType.ShouldBe(updatedEntity.EntityType); |
|||
entity.StarCount.ShouldBe(updatedEntity.StarCount); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task GetCurrentUserRatingAsync() |
|||
{ |
|||
_currentUser.Id.Returns(_cmsKitTestData.User1Id); |
|||
|
|||
var rating = await _ratingAppService.GetCurrentUserRatingAsync( |
|||
_cmsKitTestData.EntityType1, |
|||
_cmsKitTestData.EntityId1 |
|||
); |
|||
|
|||
UsingDbContext(context => |
|||
{ |
|||
var ratings = context.Set<Rating>().Where(x => |
|||
x.EntityId == _cmsKitTestData.EntityId1 && x.EntityType == _cmsKitTestData.EntityType1).ToList(); |
|||
|
|||
ratings |
|||
.Any(c => c.Id == rating.Id && c.EntityId == rating.EntityId && c.EntityType == rating.EntityType) |
|||
.ShouldBeTrue(); |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task GetGroupedStarCountsAsync() |
|||
{ |
|||
_currentUser.Id.Returns(_cmsKitTestData.User1Id); |
|||
|
|||
var ratings = await _ratingAppService.GetGroupedStarCountsAsync( |
|||
_cmsKitTestData.EntityType1, |
|||
_cmsKitTestData.EntityId1 |
|||
); |
|||
|
|||
ratings.ShouldNotBeNull(); |
|||
ratings.Count.ShouldBeGreaterThan(0); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task DeleteAsync() |
|||
{ |
|||
_currentUser.Id.Returns(_cmsKitTestData.User1Id); |
|||
|
|||
var rating = await _ratingAppService.CreateAsync( |
|||
_cmsKitTestData.EntityType1, |
|||
_cmsKitTestData.EntityId1, |
|||
new CreateUpdateRatingInput |
|||
{ |
|||
StarCount = 4 |
|||
}); |
|||
|
|||
await _ratingAppService.DeleteAsync(_cmsKitTestData.EntityType1, _cmsKitTestData.EntityId1); |
|||
|
|||
UsingDbContext(context => |
|||
{ |
|||
var deletedComment = context.Set<Rating>().FirstOrDefault(x => x.Id == rating.Id); |
|||
|
|||
deletedComment.ShouldBeNull(); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using Volo.CmsKit.Ratings; |
|||
|
|||
namespace Volo.CmsKit.EntityFrameworkCore.Ratings |
|||
{ |
|||
public class RatingRepository_Tests : RatingRepository_Tests<CmsKitEntityFrameworkCoreTestModule> |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
using Volo.CmsKit.Ratings; |
|||
using Xunit; |
|||
|
|||
namespace Volo.CmsKit.MongoDB.Ratings |
|||
{ |
|||
[Collection(MongoTestCollection.Name)] |
|||
public class RatingRepository_Tests : RatingRepository_Tests<CmsKitMongoDbTestModule> |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
using System.Threading.Tasks; |
|||
using Shouldly; |
|||
using Volo.Abp.Modularity; |
|||
using Xunit; |
|||
|
|||
namespace Volo.CmsKit.Ratings |
|||
{ |
|||
public abstract class RatingRepository_Tests<TStartupModule> : CmsKitTestBase<TStartupModule> |
|||
where TStartupModule : IAbpModule |
|||
{ |
|||
private readonly CmsKitTestData _cmsKitTestData; |
|||
private readonly IRatingRepository _ratingRepository; |
|||
|
|||
public RatingRepository_Tests() |
|||
{ |
|||
_cmsKitTestData = GetRequiredService<CmsKitTestData>(); |
|||
_ratingRepository = GetRequiredService<IRatingRepository>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task GetCurrentUserRatingAsync() |
|||
{ |
|||
var userRating = await _ratingRepository.GetCurrentUserRatingAsync(_cmsKitTestData.EntityType1, |
|||
_cmsKitTestData.EntityId1, _cmsKitTestData.User1Id); |
|||
|
|||
userRating.ShouldNotBeNull(); |
|||
userRating.EntityId.ShouldBe(_cmsKitTestData.EntityId1); |
|||
userRating.EntityType.ShouldBe(_cmsKitTestData.EntityType1); |
|||
userRating.CreatorId.ShouldBe(_cmsKitTestData.User1Id); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task GetGroupedStarCountsAsync() |
|||
{ |
|||
var list = await _ratingRepository.GetGroupedStarCountsAsync(_cmsKitTestData.EntityType1, |
|||
_cmsKitTestData.EntityId1); |
|||
|
|||
list.ShouldNotBeNull(); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue