✨ Post reactions
This commit is contained in:
parent
5844dfb657
commit
1c361b94f3
@ -80,6 +80,7 @@ public class AppDatabase(
|
|||||||
Nodes =
|
Nodes =
|
||||||
{
|
{
|
||||||
PermissionService.NewPermissionNode("group:default", "global", "posts.create", true),
|
PermissionService.NewPermissionNode("group:default", "global", "posts.create", true),
|
||||||
|
PermissionService.NewPermissionNode("group:default", "global", "posts.reactions.create", true),
|
||||||
PermissionService.NewPermissionNode("group:default", "global", "publishers.create", true),
|
PermissionService.NewPermissionNode("group:default", "global", "publishers.create", true),
|
||||||
PermissionService.NewPermissionNode("group:default", "global", "files.create", true),
|
PermissionService.NewPermissionNode("group:default", "global", "files.create", true),
|
||||||
PermissionService.NewPermissionNode("group:default", "global", "chat.create", true)
|
PermissionService.NewPermissionNode("group:default", "global", "chat.create", true)
|
||||||
|
@ -42,6 +42,7 @@ public class Post : ModelBase
|
|||||||
public int ViewsTotal { get; set; }
|
public int ViewsTotal { get; set; }
|
||||||
public int Upvotes { get; set; }
|
public int Upvotes { get; set; }
|
||||||
public int Downvotes { get; set; }
|
public int Downvotes { get; set; }
|
||||||
|
[NotMapped] public Dictionary<string, int> ReactionsCount { get; set; } = new();
|
||||||
|
|
||||||
public long? ThreadedPostId { get; set; }
|
public long? ThreadedPostId { get; set; }
|
||||||
public Post? ThreadedPost { get; set; }
|
public Post? ThreadedPost { get; set; }
|
||||||
@ -106,5 +107,6 @@ public class PostReaction : ModelBase
|
|||||||
|
|
||||||
public long PostId { get; set; }
|
public long PostId { get; set; }
|
||||||
[JsonIgnore] public Post Post { get; set; } = null!;
|
[JsonIgnore] public Post Post { get; set; } = null!;
|
||||||
|
public long AccountId { get; set; }
|
||||||
public Account.Account Account { get; set; } = null!;
|
public Account.Account Account { get; set; } = null!;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ using System.ComponentModel.DataAnnotations;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using DysonNetwork.Sphere.Account;
|
using DysonNetwork.Sphere.Account;
|
||||||
using DysonNetwork.Sphere.Permission;
|
using DysonNetwork.Sphere.Permission;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NodaTime;
|
using NodaTime;
|
||||||
@ -36,6 +37,11 @@ public class PostController(AppDatabase db, PostService ps, RelationshipService
|
|||||||
.Take(take)
|
.Take(take)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
posts = PostService.TruncatePostContent(posts);
|
posts = PostService.TruncatePostContent(posts);
|
||||||
|
|
||||||
|
var postsId = posts.Select(e => e.Id).ToList();
|
||||||
|
var reactionMaps = await ps.GetPostReactionMapBatch(postsId);
|
||||||
|
foreach (var post in posts)
|
||||||
|
post.ReactionsCount = reactionMaps[post.Id];
|
||||||
|
|
||||||
Response.Headers["X-Total"] = totalCount.ToString();
|
Response.Headers["X-Total"] = totalCount.ToString();
|
||||||
|
|
||||||
@ -62,6 +68,8 @@ public class PostController(AppDatabase db, PostService ps, RelationshipService
|
|||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
if (post is null) return NotFound();
|
if (post is null) return NotFound();
|
||||||
|
|
||||||
|
post.ReactionsCount = await ps.GetPostReactionMap(post.Id);
|
||||||
|
|
||||||
return Ok(post);
|
return Ok(post);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,13 +81,13 @@ public class PostController(AppDatabase db, PostService ps, RelationshipService
|
|||||||
var currentUser = currentUserValue as Account.Account;
|
var currentUser = currentUserValue as Account.Account;
|
||||||
var userFriends = currentUser is null ? [] : await rels.ListAccountFriends(currentUser);
|
var userFriends = currentUser is null ? [] : await rels.ListAccountFriends(currentUser);
|
||||||
|
|
||||||
var post = await db.Posts
|
var parent = await db.Posts
|
||||||
.Where(e => e.Id == id)
|
.Where(e => e.Id == id)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
if (post is null) return NotFound();
|
if (parent is null) return NotFound();
|
||||||
|
|
||||||
var totalCount = await db.Posts
|
var totalCount = await db.Posts
|
||||||
.Where(e => e.RepliedPostId == post.Id)
|
.Where(e => e.RepliedPostId == parent.Id)
|
||||||
.FilterWithVisibility(currentUser, userFriends, isListing: true)
|
.FilterWithVisibility(currentUser, userFriends, isListing: true)
|
||||||
.CountAsync();
|
.CountAsync();
|
||||||
var posts = await db.Posts
|
var posts = await db.Posts
|
||||||
@ -96,6 +104,11 @@ public class PostController(AppDatabase db, PostService ps, RelationshipService
|
|||||||
.Take(take)
|
.Take(take)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
posts = PostService.TruncatePostContent(posts);
|
posts = PostService.TruncatePostContent(posts);
|
||||||
|
|
||||||
|
var postsId = posts.Select(e => e.Id).ToList();
|
||||||
|
var reactionMaps = await ps.GetPostReactionMapBatch(postsId);
|
||||||
|
foreach (var post in posts)
|
||||||
|
post.ReactionsCount = reactionMaps[post.Id];
|
||||||
|
|
||||||
Response.Headers["X-Total"] = totalCount.ToString();
|
Response.Headers["X-Total"] = totalCount.ToString();
|
||||||
|
|
||||||
@ -194,6 +207,45 @@ public class PostController(AppDatabase db, PostService ps, RelationshipService
|
|||||||
return post;
|
return post;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PostReactionRequest
|
||||||
|
{
|
||||||
|
[MaxLength(256)] public string Symbol { get; set; } = null!;
|
||||||
|
public PostReactionAttitude Attitude { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("{id:long}/reactions")]
|
||||||
|
[Authorize]
|
||||||
|
[RequiredPermission("global", "posts.reactions.create")]
|
||||||
|
public async Task<ActionResult<PostReaction>> CreatePostReaction(long id, [FromBody] PostReactionRequest request)
|
||||||
|
{
|
||||||
|
HttpContext.Items.TryGetValue("CurrentUser", out var currentUserValue);
|
||||||
|
if (currentUserValue is not Account.Account currentUser) return Unauthorized();
|
||||||
|
var userFriends = await rels.ListAccountFriends(currentUser);
|
||||||
|
|
||||||
|
var post = await db.Posts
|
||||||
|
.Where(e => e.Id == id)
|
||||||
|
.Include(e => e.Publisher)
|
||||||
|
.FilterWithVisibility(currentUser, userFriends)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
if (post is null) return NotFound();
|
||||||
|
|
||||||
|
var isExistingReaction = await db.PostReactions
|
||||||
|
.AnyAsync(r => r.PostId == post.Id &&
|
||||||
|
r.Symbol == request.Symbol &&
|
||||||
|
r.AccountId == currentUser.Id);
|
||||||
|
var reaction = new PostReaction
|
||||||
|
{
|
||||||
|
Symbol = request.Symbol,
|
||||||
|
Attitude = request.Attitude,
|
||||||
|
PostId = post.Id,
|
||||||
|
AccountId = currentUser.Id
|
||||||
|
};
|
||||||
|
await ps.ModifyPostVotes(post, reaction, isExistingReaction);
|
||||||
|
|
||||||
|
if (isExistingReaction) return NoContent();
|
||||||
|
return Ok(reaction);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPatch("{id:long}")]
|
[HttpPatch("{id:long}")]
|
||||||
public async Task<ActionResult<Post>> UpdatePost(long id, [FromBody] PostRequest request)
|
public async Task<ActionResult<Post>> UpdatePost(long id, [FromBody] PostRequest request)
|
||||||
{
|
{
|
||||||
|
@ -125,12 +125,12 @@ public class PostService(AppDatabase db, FileService fs, ActivityService act)
|
|||||||
if (post.Content?.RootElement is { ValueKind: JsonValueKind.Array })
|
if (post.Content?.RootElement is { ValueKind: JsonValueKind.Array })
|
||||||
{
|
{
|
||||||
var searchTextBuilder = new System.Text.StringBuilder();
|
var searchTextBuilder = new System.Text.StringBuilder();
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(post.Title))
|
if (!string.IsNullOrWhiteSpace(post.Title))
|
||||||
searchTextBuilder.AppendLine(post.Title);
|
searchTextBuilder.AppendLine(post.Title);
|
||||||
if (!string.IsNullOrWhiteSpace(post.Description))
|
if (!string.IsNullOrWhiteSpace(post.Description))
|
||||||
searchTextBuilder.AppendLine(post.Description);
|
searchTextBuilder.AppendLine(post.Description);
|
||||||
|
|
||||||
foreach (var element in post.Content.RootElement.EnumerateArray())
|
foreach (var element in post.Content.RootElement.EnumerateArray())
|
||||||
{
|
{
|
||||||
if (element is { ValueKind: JsonValueKind.Object } &&
|
if (element is { ValueKind: JsonValueKind.Object } &&
|
||||||
@ -140,6 +140,7 @@ public class PostService(AppDatabase db, FileService fs, ActivityService act)
|
|||||||
searchTextBuilder.Append(insertProperty.GetString());
|
searchTextBuilder.Append(insertProperty.GetString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
post.SearchVector = EF.Functions.ToTsVector(searchTextBuilder.ToString().Trim());
|
post.SearchVector = EF.Functions.ToTsVector(searchTextBuilder.ToString().Trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,12 +226,12 @@ public class PostService(AppDatabase db, FileService fs, ActivityService act)
|
|||||||
if (post.Content?.RootElement is { ValueKind: JsonValueKind.Array })
|
if (post.Content?.RootElement is { ValueKind: JsonValueKind.Array })
|
||||||
{
|
{
|
||||||
var searchTextBuilder = new System.Text.StringBuilder();
|
var searchTextBuilder = new System.Text.StringBuilder();
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(post.Title))
|
if (!string.IsNullOrWhiteSpace(post.Title))
|
||||||
searchTextBuilder.AppendLine(post.Title);
|
searchTextBuilder.AppendLine(post.Title);
|
||||||
if (!string.IsNullOrWhiteSpace(post.Description))
|
if (!string.IsNullOrWhiteSpace(post.Description))
|
||||||
searchTextBuilder.AppendLine(post.Description);
|
searchTextBuilder.AppendLine(post.Description);
|
||||||
|
|
||||||
foreach (var element in post.Content.RootElement.EnumerateArray())
|
foreach (var element in post.Content.RootElement.EnumerateArray())
|
||||||
{
|
{
|
||||||
if (element is { ValueKind: JsonValueKind.Object } &&
|
if (element is { ValueKind: JsonValueKind.Object } &&
|
||||||
@ -240,6 +241,7 @@ public class PostService(AppDatabase db, FileService fs, ActivityService act)
|
|||||||
searchTextBuilder.Append(insertProperty.GetString());
|
searchTextBuilder.Append(insertProperty.GetString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
post.SearchVector = EF.Functions.ToTsVector(searchTextBuilder.ToString().Trim());
|
post.SearchVector = EF.Functions.ToTsVector(searchTextBuilder.ToString().Trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,6 +257,62 @@ public class PostService(AppDatabase db, FileService fs, ActivityService act)
|
|||||||
await db.SaveChangesAsync();
|
await db.SaveChangesAsync();
|
||||||
await fs.MarkUsageRangeAsync(post.Attachments, -1);
|
await fs.MarkUsageRangeAsync(post.Attachments, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculate the total number of votes for a post.
|
||||||
|
/// This function helps you save the new reactions.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="post">Post that modifying</param>
|
||||||
|
/// <param name="reaction">The new / target reaction adding / removing</param>
|
||||||
|
/// <param name="isRemoving">Indicate this operation is adding / removing</param>
|
||||||
|
public async Task ModifyPostVotes(Post post, PostReaction reaction, bool isRemoving)
|
||||||
|
{
|
||||||
|
var isExistingReaction = await db.Set<PostReaction>()
|
||||||
|
.AnyAsync(r => r.PostId == post.Id && r.AccountId == reaction.AccountId);
|
||||||
|
if (isExistingReaction) return;
|
||||||
|
|
||||||
|
if (!isRemoving)
|
||||||
|
{
|
||||||
|
db.Add(reaction);
|
||||||
|
switch (reaction.Attitude)
|
||||||
|
{
|
||||||
|
case PostReactionAttitude.Positive:
|
||||||
|
post.Upvotes++;
|
||||||
|
break;
|
||||||
|
case PostReactionAttitude.Negative:
|
||||||
|
post.Downvotes++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Dictionary<string, int>> GetPostReactionMap(long postId)
|
||||||
|
{
|
||||||
|
return await db.Set<PostReaction>()
|
||||||
|
.Where(r => r.PostId == postId)
|
||||||
|
.GroupBy(r => r.Symbol)
|
||||||
|
.ToDictionaryAsync(
|
||||||
|
g => g.Key,
|
||||||
|
g => g.Count()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Dictionary<long, Dictionary<string, int>>> GetPostReactionMapBatch(List<long> postIds)
|
||||||
|
{
|
||||||
|
return await db.Set<PostReaction>()
|
||||||
|
.Where(r => postIds.Contains(r.PostId))
|
||||||
|
.GroupBy(r => r.PostId)
|
||||||
|
.ToDictionaryAsync(
|
||||||
|
g => g.Key,
|
||||||
|
g => g.GroupBy(r => r.Symbol)
|
||||||
|
.ToDictionary(
|
||||||
|
sg => sg.Key,
|
||||||
|
sg => sg.Count()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class PostQueryExtensions
|
public static class PostQueryExtensions
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABucketArgs_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fd515fb889657fcdcace3fed90735057b458ff9e0bb60bded7c8fe8b3a4673c_003FBucketArgs_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABucketArgs_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003Fd515fb889657fcdcace3fed90735057b458ff9e0bb60bded7c8fe8b3a4673c_003FBucketArgs_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AChapterData_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ffef366b36a224d469ff150d30f9a866d23c00_003Fe6_003F64a6c0f7_003FChapterData_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AChapterData_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ffef366b36a224d469ff150d30f9a866d23c00_003Fe6_003F64a6c0f7_003FChapterData_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AClaim_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa7fdc52b6e574ae7b9822133be91162a15800_003Ff7_003Feebffd8d_003FClaim_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AClaim_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa7fdc52b6e574ae7b9822133be91162a15800_003Ff7_003Feebffd8d_003FClaim_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AControllerBase_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F0b5acdd962e549369896cece0026e556214600_003Ff6_003Fdf150bb3_003FControllerBase_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACorsPolicyBuilder_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F051ad509d0504b7ca10dedd9c2cabb9914200_003F8e_003Fb28257cb_003FCorsPolicyBuilder_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACorsPolicyBuilder_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F051ad509d0504b7ca10dedd9c2cabb9914200_003F8e_003Fb28257cb_003FCorsPolicyBuilder_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADailyTimeIntervalScheduleBuilder_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F929ef51651404d13aacd3eb8198d2961e4800_003F2b_003Ff86eadcb_003FDailyTimeIntervalScheduleBuilder_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADailyTimeIntervalScheduleBuilder_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F929ef51651404d13aacd3eb8198d2961e4800_003F2b_003Ff86eadcb_003FDailyTimeIntervalScheduleBuilder_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADailyTimeIntervalTriggerBuilderExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F929ef51651404d13aacd3eb8198d2961e4800_003F5c_003F297b8312_003FDailyTimeIntervalTriggerBuilderExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADailyTimeIntervalTriggerBuilderExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FLibrary_003FApplication_0020Support_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F929ef51651404d13aacd3eb8198d2961e4800_003F5c_003F297b8312_003FDailyTimeIntervalTriggerBuilderExtensions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user