Эндпоинты
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Knot.Modules.Auth.Domain;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
|
||||
namespace Knot.Modules.Auth.Application.Abstractions;
|
||||
|
||||
public interface IAuthDbContext
|
||||
{
|
||||
DbSet<User> Users { get; }
|
||||
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
using Knot.Shared.Kernel;
|
||||
|
||||
namespace Knot.Modules.Auth.Application.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Unit of Work специфичный для модуля Identity.
|
||||
/// </summary>
|
||||
public interface IAuthUnitOfWork : IUnitOfWork
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using Knot.Modules.Auth.Domain;
|
||||
|
||||
namespace Knot.Modules.Auth.Application.Abstractions;
|
||||
|
||||
public interface IJwtTokenProvider
|
||||
{
|
||||
string Generate(User user);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace Knot.Modules.Auth.Application.Auth.DTOs;
|
||||
|
||||
public record AuthResponseDto(
|
||||
string Token,
|
||||
AuthUserDto User
|
||||
);
|
||||
|
||||
public record AuthUserDto(
|
||||
Guid Id,
|
||||
string Username,
|
||||
string DisplayName,
|
||||
string? Email,
|
||||
string? Bio,
|
||||
string? Avatar,
|
||||
DateTime? Birthday,
|
||||
bool IsOnline,
|
||||
DateTime CreatedAt
|
||||
);
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace Knot.Modules.Auth.Application.Users.Auth;
|
||||
|
||||
public record AuthResponseDto(
|
||||
string Token,
|
||||
AuthUserDto User
|
||||
);
|
||||
|
||||
public record AuthUserDto(
|
||||
Guid Id,
|
||||
string Username,
|
||||
string DisplayName,
|
||||
string? Email,
|
||||
string? Bio,
|
||||
string? Avatar,
|
||||
DateTime? Birthday,
|
||||
bool IsOnline,
|
||||
DateTime CreatedAt
|
||||
);
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
using Knot.Shared.Kernel;
|
||||
|
||||
namespace Knot.Modules.Auth.Domain;
|
||||
|
||||
public static class AuthErrors
|
||||
{
|
||||
public static readonly Error FriendsNotFound = new Error("Friends.NotFound", "Friendship not found");
|
||||
public static readonly Error FriendsSelf = new Error("Friends.Self", "Cannot add yourself");
|
||||
public static readonly Error FriendsExists = new Error("Friends.Exists", "Friendship already exists");
|
||||
public static readonly Error UserNotFound = new Error("User.NotFound", "User not found");
|
||||
public static readonly Error IdentityInvalidCredentials = new Error("Identity.InvalidCredentials", "Неверное имя пользователя или пароль.");
|
||||
public static readonly Error IdentityRegistrationDisabled = new Error("Identity.RegistrationDisabled", "Registration is disabled by the administrator.");
|
||||
public static readonly Error IdentityUsernameNotUnique = new Error("Identity.UsernameNotUnique", "Это имя пользователя уже занято.");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using Knot.Modules.Auth.Domain;
|
||||
|
||||
namespace Knot.Modules.Auth.Domain;
|
||||
|
||||
/// <summary>
|
||||
/// Интерфейс репозитория для работы с пользователями.
|
||||
/// </summary>
|
||||
public interface IUserRepository
|
||||
{
|
||||
Task<User?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
|
||||
Task<List<User>> GetByIdsAsync(IEnumerable<Guid> ids, CancellationToken cancellationToken = default);
|
||||
Task<User?> GetByUsernameAsync(string username, CancellationToken cancellationToken = default);
|
||||
Task<bool> IsUsernameUniqueAsync(string username, CancellationToken cancellationToken = default);
|
||||
Task<List<User>> SearchUsersAsync(string query, CancellationToken cancellationToken = default);
|
||||
void Add(User user);
|
||||
void Update(User user);
|
||||
void Remove(User user);
|
||||
}
|
||||
|
||||
+2
-2
@@ -61,8 +61,8 @@ public static class MongoDbMapConfigurator
|
||||
BsonClassMap.RegisterClassMap<PollMessage>(cm =>
|
||||
{
|
||||
cm.AutoMap();
|
||||
cm.MapField("_options").SetElementName("Options");
|
||||
cm.MapField("_votes").SetElementName("Votes");
|
||||
cm.MapProperty(c => c.Options).SetElementName("_options");
|
||||
cm.MapProperty(c => c.Votes).SetElementName("_votes");
|
||||
cm.SetDiscriminator("PollMessage");
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Profiles.Domain;
|
||||
|
||||
public interface IAvatarStorageService
|
||||
{
|
||||
Task<string> UploadAsync(Stream content, string fileName, string contentType, CancellationToken ct = default);
|
||||
Task DeleteAsync(string fileId, CancellationToken ct = default);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Profiles.Domain;
|
||||
|
||||
public interface IProfileRepository
|
||||
{
|
||||
Task<ProfileDocument?> GetByIdAsync(Guid id, CancellationToken ct = default);
|
||||
Task<ProfileDocument?> GetByUsernameAsync(string username, CancellationToken ct = default);
|
||||
Task AddAsync(ProfileDocument profile, CancellationToken ct = default);
|
||||
Task UpdateAsync(ProfileDocument profile, CancellationToken ct = default);
|
||||
Task<List<ProfileDocument>> SearchAsync(string query, CancellationToken ct = default);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Profiles.Domain;
|
||||
|
||||
public interface IProfilesUnitOfWork
|
||||
{
|
||||
Task SaveChangesAsync(CancellationToken ct = default);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Knot.Modules.Profiles.Domain;
|
||||
using Knot.Shared.Kernel;
|
||||
public static class ProfilesErrors
|
||||
{
|
||||
public static readonly Error ProfileNotFound = new("Profile.NotFound", "Profile not found");
|
||||
}
|
||||
public static class IdentityErrors
|
||||
{
|
||||
public static readonly Error UserNotFound = new("Profile.NotFound", "Profile not found");
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
|
||||
namespace Knot.Modules.Settings.Application.Settings.Abstractions;
|
||||
|
||||
public interface ISettingsService
|
||||
{
|
||||
Task<SystemSettingsDto> GetSettingsAsync(CancellationToken cancellationToken = default);
|
||||
Task UpdateSettingsAsync(SystemSettingsDto settings, CancellationToken cancellationToken = default);
|
||||
SystemSettingsDto Current { get; }
|
||||
}
|
||||
|
||||
public interface ISystemSettings
|
||||
{
|
||||
SystemConfig Current { get; }
|
||||
}
|
||||
|
||||
public interface IStoriesSettings
|
||||
{
|
||||
StoriesConfig Current { get; }
|
||||
}
|
||||
|
||||
public interface IChatsSettings
|
||||
{
|
||||
ChatsConfig Current { get; }
|
||||
}
|
||||
|
||||
public interface IMessagesSettings
|
||||
{
|
||||
MessagesConfig Current { get; }
|
||||
}
|
||||
|
||||
public interface IWebRtcSettings
|
||||
{
|
||||
WebRtcConfig Current { get; }
|
||||
}
|
||||
|
||||
public interface IKlipySettings
|
||||
{
|
||||
KlipyConfig Current { get; }
|
||||
}
|
||||
|
||||
public interface IImportSettings
|
||||
{
|
||||
ImportConfig Current { get; }
|
||||
}
|
||||
|
||||
public interface IFederationSettings
|
||||
{
|
||||
FederationConfig Current { get; }
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
using System.Collections.Generic;
|
||||
using Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
|
||||
namespace Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
|
||||
public record PublicConfigDto
|
||||
{
|
||||
public SystemConfigDto System { get; init; } = new();
|
||||
public StoriesConfigDto Stories { get; init; } = new();
|
||||
public ChatsConfigDto Chats { get; init; } = new();
|
||||
public MessagesConfigDto Messages { get; init; } = new();
|
||||
public WebRtcConfigDto WebRtc { get; init; } = new();
|
||||
public KlipyConfigDto Klipy { get; init; } = new();
|
||||
public ImportConfigDto Import { get; init; } = new();
|
||||
public FederationConfigDto Federation { get; init; } = new();
|
||||
|
||||
public static PublicConfigDto FromSettings(SystemSettingsDto settings)
|
||||
{
|
||||
return new PublicConfigDto
|
||||
{
|
||||
System = new SystemConfigDto
|
||||
{
|
||||
DomainUrl = settings.System.DomainUrl,
|
||||
EnableRegistration = settings.System.EnableRegistration
|
||||
},
|
||||
Stories = new StoriesConfigDto
|
||||
{
|
||||
Enabled = settings.Stories.Enabled,
|
||||
MaxStoriesPerPeriod = settings.Stories.MaxStoriesPerPeriod,
|
||||
StoryLifetimeHours = settings.Stories.StoryLifetimeHours,
|
||||
TextStoriesEnabled = settings.Stories.TextStoriesEnabled,
|
||||
TextStoryDurationSeconds = settings.Stories.TextStoryDurationSeconds,
|
||||
MediaStoryMaxDurationSeconds = settings.Stories.MediaStoryMaxDurationSeconds,
|
||||
MaxMediaSizeBytes = settings.Stories.MaxMediaSizeBytes
|
||||
},
|
||||
Chats = new ChatsConfigDto
|
||||
{
|
||||
SupportGroups = settings.Chats.SupportGroups,
|
||||
MaxGroupParticipants = settings.Chats.MaxGroupParticipants,
|
||||
AllowChatToGroupConversion = settings.Chats.AllowChatToGroupConversion,
|
||||
EnableFolders = settings.Chats.EnableFolders
|
||||
},
|
||||
Messages = new MessagesConfigDto
|
||||
{
|
||||
DailyMessageLimitPerUser = settings.Messages.DailyMessageLimitPerUser,
|
||||
ChatMessageLimit = settings.Messages.ChatMessageLimit,
|
||||
AllowMedia = settings.Messages.AllowMedia,
|
||||
MaxMediaSizeBytes = settings.Messages.MaxMediaSizeBytes,
|
||||
AllowedMediaTypes = settings.Messages.AllowedMediaTypes,
|
||||
AllowVoiceMessages = settings.Messages.AllowVoiceMessages,
|
||||
AllowForwarding = settings.Messages.AllowForwarding,
|
||||
AllowReactions = settings.Messages.AllowReactions,
|
||||
AllowReplies = settings.Messages.AllowReplies,
|
||||
AllowQuoting = settings.Messages.AllowQuoting,
|
||||
AllowMessageDeletion = settings.Messages.AllowMessageDeletion,
|
||||
ForbidCopying = settings.Messages.ForbidCopying,
|
||||
AllowLinks = settings.Messages.AllowLinks,
|
||||
AllowPolls = settings.Messages.AllowPolls,
|
||||
AllowPinning = settings.Messages.AllowPinning
|
||||
},
|
||||
WebRtc = new WebRtcConfigDto
|
||||
{
|
||||
Enabled = settings.WebRtc.Enabled,
|
||||
EnableVoiceCalls = settings.WebRtc.EnableVoiceCalls,
|
||||
EnableVideoCalls = settings.WebRtc.EnableVideoCalls,
|
||||
EnableScreenSharing = settings.WebRtc.EnableScreenSharing,
|
||||
TurnHost = settings.WebRtc.TurnHost,
|
||||
TurnPort = settings.WebRtc.TurnPort
|
||||
},
|
||||
Klipy = new KlipyConfigDto
|
||||
{
|
||||
Enabled = settings.Klipy.Enabled,
|
||||
AppName = settings.Klipy.AppName
|
||||
},
|
||||
Import = new ImportConfigDto
|
||||
{
|
||||
Enabled = settings.Import.EnableTelegramImport
|
||||
},
|
||||
Federation = new FederationConfigDto
|
||||
{
|
||||
Enabled = settings.Federation.Enabled,
|
||||
ServerDescription = settings.Federation.ServerDescription,
|
||||
AllowedDomains = settings.Federation.AllowedDomains
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public record SystemConfigDto
|
||||
{
|
||||
public string DomainUrl { get; init; } = string.Empty;
|
||||
public bool EnableRegistration { get; init; }
|
||||
}
|
||||
|
||||
public record StoriesConfigDto
|
||||
{
|
||||
public bool Enabled { get; init; }
|
||||
public int MaxStoriesPerPeriod { get; init; }
|
||||
public int StoryLifetimeHours { get; init; }
|
||||
public bool TextStoriesEnabled { get; init; }
|
||||
public int TextStoryDurationSeconds { get; init; }
|
||||
public int MediaStoryMaxDurationSeconds { get; init; }
|
||||
public int MaxMediaSizeBytes { get; init; }
|
||||
}
|
||||
|
||||
public record ChatsConfigDto
|
||||
{
|
||||
public bool SupportGroups { get; init; }
|
||||
public int MaxGroupParticipants { get; init; }
|
||||
public bool AllowChatToGroupConversion { get; init; }
|
||||
public bool EnableFolders { get; init; }
|
||||
}
|
||||
|
||||
public record MessagesConfigDto
|
||||
{
|
||||
public int DailyMessageLimitPerUser { get; init; }
|
||||
public int ChatMessageLimit { get; init; }
|
||||
public bool AllowMedia { get; init; }
|
||||
public int MaxMediaSizeBytes { get; init; }
|
||||
public List<string> AllowedMediaTypes { get; init; } = new();
|
||||
public bool AllowVoiceMessages { get; init; }
|
||||
public bool AllowForwarding { get; init; }
|
||||
public bool AllowReactions { get; init; }
|
||||
public bool AllowReplies { get; init; }
|
||||
public bool AllowQuoting { get; init; }
|
||||
public bool AllowMessageDeletion { get; init; }
|
||||
public bool ForbidCopying { get; init; }
|
||||
public bool AllowLinks { get; init; }
|
||||
public bool AllowPolls { get; init; }
|
||||
public bool AllowPinning { get; init; }
|
||||
}
|
||||
|
||||
public record WebRtcConfigDto
|
||||
{
|
||||
public bool Enabled { get; init; }
|
||||
public bool EnableVoiceCalls { get; init; }
|
||||
public bool EnableVideoCalls { get; init; }
|
||||
public bool EnableScreenSharing { get; init; }
|
||||
public string TurnHost { get; init; } = string.Empty;
|
||||
public int TurnPort { get; init; }
|
||||
}
|
||||
|
||||
public record KlipyConfigDto
|
||||
{
|
||||
public bool Enabled { get; init; }
|
||||
public string AppName { get; init; } = string.Empty;
|
||||
}
|
||||
|
||||
public record ImportConfigDto
|
||||
{
|
||||
public bool Enabled { get; init; }
|
||||
}
|
||||
|
||||
public record FederationConfigDto
|
||||
{
|
||||
public bool Enabled { get; init; }
|
||||
public string ServerDescription { get; init; } = string.Empty;
|
||||
public List<FederationDomainConfig> AllowedDomains { get; init; } = new();
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Knot.Modules.Settings.Application.Settings.DTOs;
|
||||
|
||||
public class SystemConfig
|
||||
{
|
||||
public string ServerTimezone { get; set; } = "UTC";
|
||||
public string DomainUrl { get; set; } = "https://example.com";
|
||||
public string AdminRoute { get; set; } = "admin";
|
||||
public bool EnableRegistration { get; set; } = true;
|
||||
}
|
||||
|
||||
public class StoriesConfig
|
||||
{
|
||||
public bool Enabled { get; set; } = true;
|
||||
public int MaxStoriesPerPeriod { get; set; } = 5;
|
||||
public int StoryLifetimeHours { get; set; } = 24;
|
||||
public bool TextStoriesEnabled { get; set; } = true;
|
||||
public int TextStoryDurationSeconds { get; set; } = 15;
|
||||
public int MediaStoryMaxDurationSeconds { get; set; } = 30;
|
||||
public int MaxMediaSizeBytes { get; set; } = 15 * 1024 * 1024;
|
||||
}
|
||||
|
||||
public class ChatsConfig
|
||||
{
|
||||
public bool SupportGroups { get; set; } = true;
|
||||
public int MaxGroupParticipants { get; set; } = 200000;
|
||||
public bool AutoCleanChats { get; set; } = false;
|
||||
public bool AllowChatToGroupConversion { get; set; } = true;
|
||||
public bool EnableFolders { get; set; } = true;
|
||||
}
|
||||
|
||||
public class MessagesConfig
|
||||
{
|
||||
public int DailyMessageLimitPerUser { get; set; } = 0;
|
||||
public int ChatMessageLimit { get; set; } = 0;
|
||||
public bool AllowMedia { get; set; } = true;
|
||||
public int MaxMediaSizeBytes { get; set; } = 50 * 1024 * 1024;
|
||||
public List<string> AllowedMediaTypes { get; set; } = new() { "image/jpeg", "image/png", "video/mp4", "image/gif" };
|
||||
public bool AllowVoiceMessages { get; set; } = true;
|
||||
public bool AllowForwarding { get; set; } = true;
|
||||
public bool AllowReactions { get; set; } = true;
|
||||
public bool AllowReplies { get; set; } = true;
|
||||
public bool AllowQuoting { get; set; } = true;
|
||||
public bool AllowMessageDeletion { get; set; } = true;
|
||||
public bool ForbidCopying { get; set; } = false;
|
||||
public bool AllowLinks { get; set; } = true;
|
||||
public bool AllowPolls { get; set; } = true;
|
||||
public bool AllowPinning { get; set; } = true;
|
||||
}
|
||||
|
||||
public class WebRtcConfig
|
||||
{
|
||||
public bool Enabled { get; set; } = false;
|
||||
public bool EnableVoiceCalls { get; set; } = true;
|
||||
public bool EnableVideoCalls { get; set; } = true;
|
||||
public bool EnableScreenSharing { get; set; } = true;
|
||||
public string TurnHost { get; set; } = string.Empty;
|
||||
public int TurnPort { get; set; } = 3478;
|
||||
public string TurnUser { get; set; } = string.Empty;
|
||||
public string TurnSecret { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class KlipyConfig
|
||||
{
|
||||
public bool Enabled { get; set; } = false;
|
||||
public string ApiKey { get; set; } = string.Empty;
|
||||
public string AppName { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class ImportConfig
|
||||
{
|
||||
public bool EnableTelegramImport { get; set; } = false;
|
||||
}
|
||||
|
||||
public class FederationDomainConfig
|
||||
{
|
||||
public string Domain { get; set; } = string.Empty;
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
public string? PublicKey { get; set; }
|
||||
public RemoteCapabilities? Capabilities { get; set; }
|
||||
}
|
||||
|
||||
public class RemoteCapabilities
|
||||
{
|
||||
public bool AllowMedia { get; set; }
|
||||
public bool AllowPolls { get; set; }
|
||||
public bool AllowVoiceMessages { get; set; }
|
||||
public bool AllowVideoCalls { get; set; }
|
||||
public bool AllowScreenSharing { get; set; }
|
||||
}
|
||||
|
||||
public class FederationConfig
|
||||
{
|
||||
public bool Enabled { get; set; } = false;
|
||||
public string ServerDescription { get; set; } = string.Empty;
|
||||
public string? PrivateKey { get; set; }
|
||||
public string? PublicKey { get; set; }
|
||||
public List<FederationDomainConfig> AllowedDomains { get; set; } = new();
|
||||
}
|
||||
|
||||
public class SystemSettingsDto
|
||||
{
|
||||
public SystemConfig System { get; set; } = new();
|
||||
public StoriesConfig Stories { get; set; } = new();
|
||||
public ChatsConfig Chats { get; set; } = new();
|
||||
public MessagesConfig Messages { get; set; } = new();
|
||||
public WebRtcConfig WebRtc { get; set; } = new();
|
||||
public KlipyConfig Klipy { get; set; } = new();
|
||||
public ImportConfig Import { get; set; } = new();
|
||||
public FederationConfig Federation { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Stories.Application.Abstractions;
|
||||
|
||||
public interface IKlipyClient
|
||||
{
|
||||
Task<bool> TestConnectionAsync(string apiKey, CancellationToken ct = default);
|
||||
Task<List<string>> SearchVideosAsync(string apiKey, string query, int limit, CancellationToken ct = default);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Knot.Modules.Stories.Domain;
|
||||
using Knot.Modules.Relations.Domain;
|
||||
|
||||
namespace Knot.Modules.Stories.Application.Abstractions;
|
||||
|
||||
public interface IStoriesDbContext
|
||||
{
|
||||
DbSet<Story> Stories { get; }
|
||||
DbSet<Friendship> Friendships { get; }
|
||||
DbSet<StoryViewer> StoryViewers { get; }
|
||||
DbSet<TEntity> Set<TEntity>() where TEntity : class;
|
||||
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public interface IStoriesUnitOfWork
|
||||
{
|
||||
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using Knot.Modules.Stories.Application.Abstractions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Knot.Modules.Stories.Infrastructure.External;
|
||||
|
||||
public sealed class KlipyClient : IKlipyClient
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public KlipyClient(HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
}
|
||||
|
||||
public async Task<bool> TestConnectionAsync(string apiKey, CancellationToken ct = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.klipy.co/v1/trending?limit=1");
|
||||
request.Headers.Add("X-API-KEY", apiKey);
|
||||
|
||||
using var response = await _httpClient.SendAsync(request, ct);
|
||||
return response.IsSuccessStatusCode;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<string>> SearchVideosAsync(string apiKey, string query, int limit, CancellationToken ct = default)
|
||||
{
|
||||
// В реальном проекте: десериализация ответа от Klipy API
|
||||
return new List<string>();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user