Compare commits
4 Commits
32977d9580
...
e624c2bb3e
Author | SHA1 | Date | |
---|---|---|---|
e624c2bb3e
|
|||
9631cd3edd
|
|||
f4a659fce5
|
|||
1ded811b36
|
@@ -1,30 +1,25 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<Sdk Name="Aspire.AppHost.Sdk" Version="9.5.1" />
|
||||||
<Sdk Name="Aspire.AppHost.Sdk" Version="9.5.0"/>
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
<PropertyGroup>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<UserSecretsId>a68b3195-a00d-40c2-b5ed-d675356b7cde</UserSecretsId>
|
||||||
<Nullable>enable</Nullable>
|
<RootNamespace>DysonNetwork.Control</RootNamespace>
|
||||||
<UserSecretsId>a68b3195-a00d-40c2-b5ed-d675356b7cde</UserSecretsId>
|
</PropertyGroup>
|
||||||
<RootNamespace>DysonNetwork.Control</RootNamespace>
|
<ItemGroup>
|
||||||
</PropertyGroup>
|
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.5.1" />
|
||||||
|
<PackageReference Include="Aspire.Hosting.Docker" Version="9.4.2-preview.1.25428.12" />
|
||||||
<ItemGroup>
|
<PackageReference Include="Aspire.Hosting.Nats" Version="9.5.1" />
|
||||||
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.5.0" />
|
<PackageReference Include="Aspire.Hosting.Redis" Version="9.5.1" />
|
||||||
<PackageReference Include="Aspire.Hosting.Docker" Version="9.4.2-preview.1.25428.12" />
|
</ItemGroup>
|
||||||
<PackageReference Include="Aspire.Hosting.Nats" Version="9.5.0" />
|
<ItemGroup>
|
||||||
<PackageReference Include="Aspire.Hosting.Redis" Version="9.5.0" />
|
<ProjectReference Include="..\DysonNetwork.Develop\DysonNetwork.Develop.csproj" />
|
||||||
</ItemGroup>
|
<ProjectReference Include="..\DysonNetwork.Drive\DysonNetwork.Drive.csproj" />
|
||||||
|
<ProjectReference Include="..\DysonNetwork.Pass\DysonNetwork.Pass.csproj" />
|
||||||
<ItemGroup>
|
<ProjectReference Include="..\DysonNetwork.Ring\DysonNetwork.Ring.csproj" />
|
||||||
<ProjectReference Include="..\DysonNetwork.Develop\DysonNetwork.Develop.csproj" />
|
<ProjectReference Include="..\DysonNetwork.Sphere\DysonNetwork.Sphere.csproj" />
|
||||||
<ProjectReference Include="..\DysonNetwork.Drive\DysonNetwork.Drive.csproj" />
|
<ProjectReference Include="..\DysonNetwork.Gateway\DysonNetwork.Gateway.csproj" />
|
||||||
<ProjectReference Include="..\DysonNetwork.Pass\DysonNetwork.Pass.csproj" />
|
</ItemGroup>
|
||||||
<ProjectReference Include="..\DysonNetwork.Ring\DysonNetwork.Ring.csproj" />
|
</Project>
|
||||||
<ProjectReference Include="..\DysonNetwork.Sphere\DysonNetwork.Sphere.csproj" />
|
|
||||||
<ProjectReference Include="..\DysonNetwork.Gateway\DysonNetwork.Gateway.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@@ -10,7 +10,9 @@
|
|||||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||||
"DOTNET_ENVIRONMENT": "Development",
|
"DOTNET_ENVIRONMENT": "Development",
|
||||||
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21175",
|
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21175",
|
||||||
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22189"
|
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22189",
|
||||||
|
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21260",
|
||||||
|
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22052"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"http": {
|
"http": {
|
||||||
@@ -22,8 +24,9 @@
|
|||||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||||
"DOTNET_ENVIRONMENT": "Development",
|
"DOTNET_ENVIRONMENT": "Development",
|
||||||
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19163",
|
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19163",
|
||||||
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20185"
|
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20185",
|
||||||
|
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:22108"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
19
DysonNetwork.Shared/Models/ActivityHeatmap.cs
Normal file
19
DysonNetwork.Shared/Models/ActivityHeatmap.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using NodaTime;
|
||||||
|
|
||||||
|
namespace DysonNetwork.Shared.Models;
|
||||||
|
|
||||||
|
public class ActivityHeatmap
|
||||||
|
{
|
||||||
|
public string Unit { get; set; } = "posts";
|
||||||
|
|
||||||
|
public Instant PeriodStart { get; set; }
|
||||||
|
public Instant PeriodEnd { get; set; }
|
||||||
|
|
||||||
|
public List<ActivityHeatmapItem> Items { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ActivityHeatmapItem
|
||||||
|
{
|
||||||
|
public Instant Date { get; set; }
|
||||||
|
public int Count { get; set; }
|
||||||
|
}
|
15
DysonNetwork.Shared/Models/Autocompletion.cs
Normal file
15
DysonNetwork.Shared/Models/Autocompletion.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace DysonNetwork.Shared.Models;
|
||||||
|
|
||||||
|
public class AutocompletionRequest
|
||||||
|
{
|
||||||
|
[Required] public string Content { get; set; } = null!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Autocompletion
|
||||||
|
{
|
||||||
|
public string Type { get; set; } = null!;
|
||||||
|
public string Keyword { get; set; } = null!;
|
||||||
|
public object Data { get; set; } = null!;
|
||||||
|
}
|
121
DysonNetwork.Sphere/Autocompletion/AutocompletionService.cs
Normal file
121
DysonNetwork.Sphere/Autocompletion/AutocompletionService.cs
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace DysonNetwork.Sphere.Autocompletion;
|
||||||
|
|
||||||
|
public class AutocompletionService(AppDatabase db)
|
||||||
|
{
|
||||||
|
public async Task<List<DysonNetwork.Shared.Models.Autocompletion>> GetAutocompletion(string content, int limit = 10)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(content))
|
||||||
|
return [];
|
||||||
|
|
||||||
|
if (content.StartsWith('@'))
|
||||||
|
{
|
||||||
|
var afterAt = content[1..];
|
||||||
|
string type;
|
||||||
|
string query;
|
||||||
|
if (afterAt.Contains('/'))
|
||||||
|
{
|
||||||
|
var parts = afterAt.Split('/', 2);
|
||||||
|
type = parts[0];
|
||||||
|
query = parts.Length > 1 ? parts[1] : "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
type = "u";
|
||||||
|
query = afterAt;
|
||||||
|
}
|
||||||
|
return await AutocompleteAt(type, query, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!content.StartsWith(':')) return [];
|
||||||
|
{
|
||||||
|
var query = content[1..];
|
||||||
|
return await AutocompleteSticker(query, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<DysonNetwork.Shared.Models.Autocompletion>> AutocompleteAt(string type, string query, int limit)
|
||||||
|
{
|
||||||
|
var results = new List<DysonNetwork.Shared.Models.Autocompletion>();
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case "p":
|
||||||
|
var publishers = await db.Publishers
|
||||||
|
.Where(p => EF.Functions.Like(p.Name, $"{query}%") || EF.Functions.Like(p.Nick, $"{query}%"))
|
||||||
|
.Take(limit)
|
||||||
|
.Select(p => new DysonNetwork.Shared.Models.Autocompletion
|
||||||
|
{
|
||||||
|
Type = "publisher",
|
||||||
|
Keyword = p.Name,
|
||||||
|
Data = p
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
results.AddRange(publishers);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "r":
|
||||||
|
var realms = await db.Realms
|
||||||
|
.Where(r => EF.Functions.Like(r.Slug, $"{query}%") || EF.Functions.Like(r.Name, $"{query}%"))
|
||||||
|
.Take(limit)
|
||||||
|
.Select(r => new DysonNetwork.Shared.Models.Autocompletion
|
||||||
|
{
|
||||||
|
Type = "realm",
|
||||||
|
Keyword = r.Slug,
|
||||||
|
Data = r
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
results.AddRange(realms);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "c":
|
||||||
|
var chats = await db.ChatRooms
|
||||||
|
.Where(c => c.Name != null && EF.Functions.Like(c.Name, $"{query}%"))
|
||||||
|
.Take(limit)
|
||||||
|
.Select(c => new DysonNetwork.Shared.Models.Autocompletion
|
||||||
|
{
|
||||||
|
Type = "chat",
|
||||||
|
Keyword = c.Name!,
|
||||||
|
Data = c
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
results.AddRange(chats);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<DysonNetwork.Shared.Models.Autocompletion>> AutocompleteSticker(string query, int limit)
|
||||||
|
{
|
||||||
|
var stickers = await db.Stickers
|
||||||
|
.Include(s => s.Pack)
|
||||||
|
.Where(s => EF.Functions.Like(s.Slug, $"{query}%"))
|
||||||
|
.Take(limit)
|
||||||
|
.Select(s => new DysonNetwork.Shared.Models.Autocompletion
|
||||||
|
{
|
||||||
|
Type = "sticker",
|
||||||
|
Keyword = s.Slug,
|
||||||
|
Data = s
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// Also possibly search by pack prefix? But user said slug after :
|
||||||
|
// Perhaps combine or search packs
|
||||||
|
var packs = await db.StickerPacks
|
||||||
|
.Where(p => EF.Functions.Like(p.Prefix, $"{query}%"))
|
||||||
|
.Take(limit)
|
||||||
|
.Select(p => new DysonNetwork.Shared.Models.Autocompletion
|
||||||
|
{
|
||||||
|
Type = "sticker_pack",
|
||||||
|
Keyword = p.Prefix,
|
||||||
|
Data = p
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var results = stickers.Concat(packs).Take(limit).ToList();
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
@@ -4,6 +4,7 @@ using DysonNetwork.Shared.Auth;
|
|||||||
using DysonNetwork.Shared.Data;
|
using DysonNetwork.Shared.Data;
|
||||||
using DysonNetwork.Shared.Models;
|
using DysonNetwork.Shared.Models;
|
||||||
using DysonNetwork.Shared.Proto;
|
using DysonNetwork.Shared.Proto;
|
||||||
|
using DysonNetwork.Sphere.Autocompletion;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@@ -17,7 +18,8 @@ public partial class ChatController(
|
|||||||
ChatService cs,
|
ChatService cs,
|
||||||
ChatRoomService crs,
|
ChatRoomService crs,
|
||||||
FileService.FileServiceClient files,
|
FileService.FileServiceClient files,
|
||||||
AccountService.AccountServiceClient accounts
|
AccountService.AccountServiceClient accounts,
|
||||||
|
AutocompletionService aus
|
||||||
) : ControllerBase
|
) : ControllerBase
|
||||||
{
|
{
|
||||||
public class MarkMessageReadRequest
|
public class MarkMessageReadRequest
|
||||||
@@ -329,4 +331,20 @@ public partial class ChatController(
|
|||||||
var response = await cs.GetSyncDataAsync(roomId, request.LastSyncTimestamp);
|
var response = await cs.GetSyncDataAsync(roomId, request.LastSyncTimestamp);
|
||||||
return Ok(response);
|
return Ok(response);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
[HttpGet("{roomId:guid}/autocomplete")]
|
||||||
|
public async Task<ActionResult<List<DysonNetwork.Shared.Models.Autocompletion>>> ChatAutoComplete([FromBody] AutocompletionRequest request, Guid roomId)
|
||||||
|
{
|
||||||
|
if (HttpContext.Items["CurrentUser"] is not Account currentUser)
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
|
var accountId = Guid.Parse(currentUser.Id);
|
||||||
|
var isMember = await db.ChatMembers
|
||||||
|
.AnyAsync(m => m.AccountId == accountId && m.ChatRoomId == roomId && m.JoinedAt != null && m.LeaveAt == null);
|
||||||
|
if (!isMember)
|
||||||
|
return StatusCode(403, "You are not a member of this chat room.");
|
||||||
|
|
||||||
|
var result = await aus.GetAutocompletion(request.Content, limit: 10);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -45,7 +45,8 @@ public class ChatRoomService(
|
|||||||
if (member is not null) return member;
|
if (member is not null) return member;
|
||||||
|
|
||||||
member = await db.ChatMembers
|
member = await db.ChatMembers
|
||||||
.Where(m => m.AccountId == accountId && m.ChatRoomId == chatRoomId && m.JoinedAt != null && m.LeaveAt == null)
|
.Where(m => m.AccountId == accountId && m.ChatRoomId == chatRoomId && m.JoinedAt != null &&
|
||||||
|
m.LeaveAt == null)
|
||||||
.Include(m => m.ChatRoom)
|
.Include(m => m.ChatRoom)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
|
|
||||||
@@ -95,7 +96,7 @@ public class ChatRoomService(
|
|||||||
? await db.ChatMembers
|
? await db.ChatMembers
|
||||||
.Where(m => directRoomsId.Contains(m.ChatRoomId))
|
.Where(m => directRoomsId.Contains(m.ChatRoomId))
|
||||||
.Where(m => m.AccountId != userId)
|
.Where(m => m.AccountId != userId)
|
||||||
.Where(m => m.JoinedAt != null && m.LeaveAt == null)
|
// Ignored the joined at condition here to keep showing userinfo when other didn't accept the invite of DM
|
||||||
.ToListAsync()
|
.ToListAsync()
|
||||||
: [];
|
: [];
|
||||||
members = await LoadMemberAccounts(members);
|
members = await LoadMemberAccounts(members);
|
||||||
@@ -156,12 +157,15 @@ public class ChatRoomService(
|
|||||||
var accountIds = members.Select(m => m.AccountId).ToList();
|
var accountIds = members.Select(m => m.AccountId).ToList();
|
||||||
var accounts = (await accountsHelper.GetAccountBatch(accountIds)).ToDictionary(a => Guid.Parse(a.Id), a => a);
|
var accounts = (await accountsHelper.GetAccountBatch(accountIds)).ToDictionary(a => Guid.Parse(a.Id), a => a);
|
||||||
|
|
||||||
return [.. members.Select(m =>
|
return
|
||||||
{
|
[
|
||||||
if (accounts.TryGetValue(m.AccountId, out var account))
|
.. members.Select(m =>
|
||||||
m.Account = SnAccount.FromProtoValue(account);
|
{
|
||||||
return m;
|
if (accounts.TryGetValue(m.AccountId, out var account))
|
||||||
})];
|
m.Account = SnAccount.FromProtoValue(account);
|
||||||
|
return m;
|
||||||
|
})
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
private const string ChatRoomSubscribeKeyPrefix = "chatroom:subscribe:";
|
private const string ChatRoomSubscribeKeyPrefix = "chatroom:subscribe:";
|
||||||
@@ -192,4 +196,4 @@ public class ChatRoomService(
|
|||||||
var keys = await cache.GetGroupKeysAsync(group);
|
var keys = await cache.GetGroupKeysAsync(group);
|
||||||
return keys.Select(k => Guid.Parse(k.Split(':').Last())).ToList();
|
return keys.Select(k => Guid.Parse(k.Split(':').Last())).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -37,6 +37,14 @@ public class PublisherController(
|
|||||||
|
|
||||||
return Ok(publisher);
|
return Ok(publisher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("{name}/heatmap")]
|
||||||
|
public async Task<ActionResult<ActivityHeatmap>> GetPublisherHeatmap(string name)
|
||||||
|
{
|
||||||
|
var heatmap = await ps.GetPublisherHeatmap(name);
|
||||||
|
if (heatmap is null) return NotFound();
|
||||||
|
return Ok(heatmap);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet("{name}/stats")]
|
[HttpGet("{name}/stats")]
|
||||||
public async Task<ActionResult<PublisherService.PublisherStats>> GetPublisherStats(string name)
|
public async Task<ActionResult<PublisherService.PublisherStats>> GetPublisherStats(string name)
|
||||||
@@ -693,4 +701,4 @@ public class PublisherController(
|
|||||||
|
|
||||||
return NoContent();
|
return NoContent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -283,6 +283,7 @@ public class PublisherService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private const string PublisherStatsCacheKey = "PublisherStats_{0}";
|
private const string PublisherStatsCacheKey = "PublisherStats_{0}";
|
||||||
|
private const string PublisherHeatmapCacheKey = "PublisherHeatmap_{0}";
|
||||||
private const string PublisherFeatureCacheKey = "PublisherFeature_{0}_{1}";
|
private const string PublisherFeatureCacheKey = "PublisherFeature_{0}_{1}";
|
||||||
|
|
||||||
public async Task<PublisherStats?> GetPublisherStats(string name)
|
public async Task<PublisherStats?> GetPublisherStats(string name)
|
||||||
@@ -325,6 +326,45 @@ public class PublisherService(
|
|||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ActivityHeatmap?> GetPublisherHeatmap(string name)
|
||||||
|
{
|
||||||
|
var cacheKey = string.Format(PublisherHeatmapCacheKey, name);
|
||||||
|
var heatmap = await cache.GetAsync<ActivityHeatmap>(cacheKey);
|
||||||
|
if (heatmap is not null)
|
||||||
|
return heatmap;
|
||||||
|
|
||||||
|
var publisher = await db.Publishers.FirstOrDefaultAsync(e => e.Name == name);
|
||||||
|
if (publisher is null) return null;
|
||||||
|
|
||||||
|
var now = SystemClock.Instance.GetCurrentInstant();
|
||||||
|
var periodStart = now.Minus(Duration.FromDays(365));
|
||||||
|
var periodEnd = now;
|
||||||
|
|
||||||
|
var postGroups = await db.Posts
|
||||||
|
.Where(p => p.PublisherId == publisher.Id && p.CreatedAt >= periodStart && p.CreatedAt <= periodEnd)
|
||||||
|
.Select(p => p.CreatedAt.InUtc().Date)
|
||||||
|
.GroupBy(d => d)
|
||||||
|
.Select(g => new { Date = g.Key, Count = g.Count() })
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var items = postGroups.Select(p => new ActivityHeatmapItem
|
||||||
|
{
|
||||||
|
Date = p.Date.AtStartOfDayInZone(DateTimeZone.Utc).ToInstant(),
|
||||||
|
Count = p.Count
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
heatmap = new ActivityHeatmap
|
||||||
|
{
|
||||||
|
Unit = "posts",
|
||||||
|
PeriodStart = periodStart,
|
||||||
|
PeriodEnd = periodEnd,
|
||||||
|
Items = items.OrderBy(i => i.Date).ToList()
|
||||||
|
};
|
||||||
|
|
||||||
|
await cache.SetAsync(cacheKey, heatmap, TimeSpan.FromMinutes(5));
|
||||||
|
return heatmap;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task SetFeatureFlag(Guid publisherId, string flag)
|
public async Task SetFeatureFlag(Guid publisherId, string flag)
|
||||||
{
|
{
|
||||||
var featureFlag = await db.PublisherFeatures
|
var featureFlag = await db.PublisherFeatures
|
||||||
@@ -397,4 +437,4 @@ public class PublisherService(
|
|||||||
return m;
|
return m;
|
||||||
})];
|
})];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,6 +15,7 @@ using System.Text.Json.Serialization;
|
|||||||
using System.Threading.RateLimiting;
|
using System.Threading.RateLimiting;
|
||||||
using DysonNetwork.Shared.Cache;
|
using DysonNetwork.Shared.Cache;
|
||||||
using DysonNetwork.Shared.GeoIp;
|
using DysonNetwork.Shared.GeoIp;
|
||||||
|
using DysonNetwork.Sphere.Autocompletion;
|
||||||
using DysonNetwork.Sphere.WebReader;
|
using DysonNetwork.Sphere.WebReader;
|
||||||
using DysonNetwork.Sphere.Discovery;
|
using DysonNetwork.Sphere.Discovery;
|
||||||
using DysonNetwork.Sphere.Poll;
|
using DysonNetwork.Sphere.Poll;
|
||||||
@@ -118,6 +119,7 @@ public static class ServiceCollectionExtensions
|
|||||||
services.AddScoped<WebFeedService>();
|
services.AddScoped<WebFeedService>();
|
||||||
services.AddScoped<DiscoveryService>();
|
services.AddScoped<DiscoveryService>();
|
||||||
services.AddScoped<PollService>();
|
services.AddScoped<PollService>();
|
||||||
|
services.AddScoped<AutocompletionService>();
|
||||||
|
|
||||||
var translationProvider = configuration["Translation:Provider"]?.ToLower();
|
var translationProvider = configuration["Translation:Provider"]?.ToLower();
|
||||||
switch (translationProvider)
|
switch (translationProvider)
|
||||||
@@ -129,4 +131,4 @@ public static class ServiceCollectionExtensions
|
|||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user