mirror of
https://github.com/Govor-team/Govor.git
synced 2026-07-21 11:44:56 +00:00
firebase sdk update + sql options
This commit is contained in:
+2
-1
@@ -42,9 +42,10 @@ appsettings.*.json
|
||||
## JetBrains Rider
|
||||
.idea/
|
||||
|
||||
## Logs
|
||||
## Logs & other
|
||||
*.log
|
||||
logs/
|
||||
uploads/
|
||||
|
||||
## Папки для публикации
|
||||
publish/
|
||||
|
||||
@@ -158,20 +158,42 @@ public static class ConfigurationProgramExtensions
|
||||
{
|
||||
services.AddDbContext<GovorDbContext>(options =>
|
||||
{
|
||||
options
|
||||
.UseMySql(
|
||||
configuration.GetConnectionString(nameof(GovorDbContext)),
|
||||
new MySqlServerVersion(new Version(8, 0, 21))
|
||||
);
|
||||
options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
|
||||
var connectionString = configuration.GetConnectionString(nameof(GovorDbContext));
|
||||
|
||||
options.UseMySql(
|
||||
connectionString,
|
||||
new MySqlServerVersion(new Version(8, 0, 21)),
|
||||
mySqlOptions =>
|
||||
{
|
||||
mySqlOptions.EnableRetryOnFailure(
|
||||
maxRetryCount: 5,
|
||||
maxRetryDelay: TimeSpan.FromSeconds(5),
|
||||
errorNumbersToAdd: null);
|
||||
});
|
||||
|
||||
options.EnableSensitiveDataLogging();
|
||||
options.EnableDetailedErrors();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddDbContext<GovorDbContext>(options =>
|
||||
{
|
||||
options.UseNpgsql(configuration.GetConnectionString(nameof(GovorDbContext)));
|
||||
options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
|
||||
options.UseNpgsql(
|
||||
configuration.GetConnectionString(nameof(GovorDbContext)),
|
||||
npgsqlOptions =>
|
||||
{
|
||||
// retry for transient failures
|
||||
npgsqlOptions.EnableRetryOnFailure(
|
||||
maxRetryCount: 5,
|
||||
maxRetryDelay: TimeSpan.FromSeconds(5),
|
||||
errorCodesToAdd: null);
|
||||
});
|
||||
|
||||
//options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
|
||||
|
||||
options.EnableSensitiveDataLogging();
|
||||
options.EnableDetailedErrors();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,6 @@ public class ProfileController : ControllerBase
|
||||
userId);
|
||||
|
||||
var mediaInfo = await _mediaService.UploadMediaAsync(media);
|
||||
|
||||
await _profileService.SetNewIcon(userId, mediaInfo.MediaId);
|
||||
|
||||
return Ok(mediaInfo);
|
||||
|
||||
@@ -51,7 +51,6 @@
|
||||
"фашист",
|
||||
"фашизм",
|
||||
"рейх",
|
||||
"сс",
|
||||
"гестапо",
|
||||
|
||||
"свинорез",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"type": "service_account",
|
||||
"project_id": "govor-ad008",
|
||||
"private_key_id": "c86cedafc5fd26278d812d1eb04281415076b70b",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxSZEVKcgorEeR\nIMobn6Fa2WDRZTwqm6A/yQ4gMJb673TvOSn7ukAZoV/IoZOR8fz84OdLzoEP0/Gu\nYtCvKdc/rsVdPVnLZZxxpk+cYbrfSstdke55E67tLjtlfF7XZn3OSQ2lRszff80z\n78DHWORaSGUb4UKrB8mnvPFZmM8lDzwmslnskQBB97nIDBxsBdUD2jw2n70kjfM5\nFgNX814PEztSqwC7nNkXl2MZxWSOP7ppjTsJrDfWGhFJ1faCS+sW3KzzI4XHMUyG\nd++Oxs7QK/jcD0/NwDMjMycRv/6WZgn2ItY+EUXza/6NMS+RikXwEiZjkfvte5IU\nkTk3Wb+nAgMBAAECggEAEAQN28QVBXue0YENURaILJ1jrjb/ivfZL7n5kTXihdPZ\nE/1tigSm4sndzdGu86nRSYUF0CbdKPFkLXVW1eQpQmMHCGfQ81uAGRJFseJwT9jB\na3gR+5UoIdwh2Ia2SK5FIjweQ/aT7oLspkr79uZUZsWQgMbGT44aDRG4GfiAih/i\nCye02cBUt6LwYTSyn4toX/Hsnoew60qLsyo6UiyE18eOrrFaK0Rcc8ia8jJ7j4K/\niKywX+PiK9z9dp95G/bpspfPkTh1XE1LEL8ArglnOLSJtbewmOrGK/PODo6EaVIU\nH4uv/0ThIkjDN5PvvZZkBXLdZ/mLyAPa2Xh5hvih0QKBgQDqkSSTAJNQG3UgH3cq\n8So4XuFbsWB4zCDqpBz+WitmKJUzYNhXyTZ3Sx7JbculNFESaX2lmeHTW/7vwa/Z\nZrt6npSlR6Ln3AitCyZRE46tBlaN3kBJvTolRLZvBS+Rq/bYedNyN8Ls18yoQcUj\nsGn1Jetjl3M8QQl7AmnOb2aclwKBgQDBfJJ34ba2LwsQTTwdbCeyCGOAyj59qQaq\nB4oGKb24SDJMbOGa7p17PSwvnRUmdNXmT9QKawBf3H2d3MWBpHW1024Ycg64ZD6Y\nLCpye7wLeNs3OPyFDfpi7uXKbpBA/cjU1uI1eqXC197VmU/BAk6TxlRijY3zK1kU\n9bA0pb2HcQKBgHBV1mg4TFR+8dbSeuWr3YZlmhOpnQP87n6w3dnKISKpqNqUNMfF\n6zmyViotVOvnZDQnJS9bxNTOKAd2gNri4kJVE+cbqZ7Ut6r3vf/yF9AxSt5iY/Ns\nlh4nDB+bIi7nZi5CGcuHfOikaLTj2p++6t+mq1Zkv6FJnFq2yyk8HK49AoGBAJ5N\nADyq4+TsWj3tItjjqxqCuH4feb8vsi8cWfWu4vTJxLU4g+BRh3DT3Lnb5/j9sB9t\ngos/fh/v8qpcfQ8TcebgY/wGHTsJcRjpUZU23OP57kihDCEEDa4xzLmxeb5ipJRW\ndt7QSJxAJ6VUeKbt70ICCvpS3CdueMSoOpDoZUdRAoGBALY0kemgKgLxHDNXZEjI\n3/ndIdea5aI2q2UpZHEdfLcCE1Fb/bVjtx9ZTLsxxm25L7sdqHqxivMxmEMhgxc4\nXzvUtA22i4FIF2g6M/31gWeFtHvJWczeit/FMsw271HxPflVuuf4cxaIcYkccJTd\nQhbyfbGJAhVBR02CeDXM3lOy\n-----END PRIVATE KEY-----\n",
|
||||
"private_key_id": "dc49ff3b29359c0e65ee9c1c1e0e4e825928e16b",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDFUuoGpZxXiEVN\nBlfWCUEnwjyev+rcPb2oMo1jKcKJh24/cHfaToThEMO6G53CpatpoB2/TFSE3hxM\ncjSy/wmCngAmqy8xKaVeg8YL4jxLlHVormgPzP1Dmoe77YSEItf7RlR13tyNzXgj\ncHHvfaaDCffwLsUF7vTleNS9w9CF03+8VfjfT2Ggu7WChpsxWrF5EUboWltNIAbQ\nmOBWCnWRbas/sMA5ijKpcg2g8f6Xj2OdUeK+229xgtBFogMgS3/U54WCKCQtDSQo\nP7a1w93nFzL3bMs7lACKBkb00VnzSQN/FoHyQRoQrwlkr309u8ZRAK142m4yFugR\nSYnDnnXRAgMBAAECggEAIPvyKLhIQQ2DYBO+XQXhAU9jqLm1/ajIajRBFCFn5mtg\nD3SyZCiZ57FQtmxlW6Mr2xUrw81zl141ZsX0bzNYmJ/msJAO7G3kub7XPSdNIukn\nEx+MP4/pigJrzAsxCpF0fwlLlwRw47dD7NCgCwN68Q6ahmibAJnoD++5yBrSYXwk\n7a1nJQhNg5AWnXSk8vCxFyhrKzMa0yh0BtWYeMVY74rSNIlvgkw8dzZEuLdnRn7f\nL4jUbyHmCIiSGt5VLTs273YqOrN5t5UW8lJUCdL8wOMJH01uWJVzKjrRLmhp3fKp\n6NZHyLpaPWbkKo0X6+PQV84RUl5+0/CkJ469G5Zz0QKBgQDtjDmsKxXoa0i1tgRq\nEnZd4WU1aEf22zcm+nWODQoFEDFYAJLGabqTuPo1oJVEo8DeQiSRUaao+ac4HHd5\nhnieTJzD12CgLSwVwy6pJN2Sbiw0sa36V7m3s+0kqPyyv+ybFbGJR3C3IAO8c0F5\nJc0bDReXNXJs/dw1fF/GMaT4BQKBgQDUptBbUojRzR5yzhdvmAqsWVBFG0Em3QAN\nKg/9GVuhKQahc7RHom+JLEYeFVgThohyXyA7iAZ0k1Mnubxa0+KIq5NqdauIsflA\n4lZ4zLjOemUjp2OAMumYvXfoAqaKfvHx8iovfTgehf1bWdtSbKwKXCJEK/7Xtw69\nU5PqommsXQKBgQCalzkpHFkDil4lMzEoPp+ddQPCf/zlX8BCs5gxO7cbmHAkTys1\nyLTNUgIzSDAcHV10xyK5F6QYL3BtickO4z439q/Gm7GcTAl2mDETjpRLqTtHh6Ir\nW0/Xh1Z7FyZsxY4bV0DUkBOAeWs1BuTDDKCwTBLgKr4uw/69KBXEC6bKaQKBgQDP\n/SilaaBws9MoLvM1Ltyhnemo7fNXc6jtN0rUHs1EX8Agge6+cd3tqOQb4Hx4/IjQ\ndMIt9+l4c/BNVpknrT5QtqBE7DqORKSqFbbGCFZpfcUWjk3/wcxAnHB++LizlV5H\narhgInWVRTB8/PJLOAc9SsgpLW7gxicgfnKad6gr8QKBgAQIQEC9HPzdFikoxOmW\nlOYaWqDl2P294C2ESGv8ti6Boxx9PsE8k2CrFYXensvk5b4+vV9XTe67PTZ2ZGJS\nLkN77+iDbP8zCysnDWyxCAwJeEmK/eVvBtMA7Juzf3ikF5FxmwXPvSRY4oPd+2cs\neejPkHyvPWNRrZryc5e+9dSJ\n-----END PRIVATE KEY-----\n",
|
||||
"client_email": "firebase-adminsdk-fbsvc@govor-ad008.iam.gserviceaccount.com",
|
||||
"client_id": "115697205969744490044",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
|
||||
@@ -49,13 +49,36 @@ public class LocalStorageService : IStorageService
|
||||
|
||||
public async Task RemoveAsync(string url)
|
||||
{
|
||||
var path = Path.Combine(_storagePath, url);
|
||||
if (string.IsNullOrWhiteSpace(url))
|
||||
throw new ArgumentException("Invalid file url");
|
||||
|
||||
if (File.Exists(path))
|
||||
var rootPath = Path.GetFullPath(_storagePath);
|
||||
|
||||
var fullPath = Path.GetFullPath(Path.Combine(rootPath, url));
|
||||
|
||||
if (!fullPath.StartsWith(rootPath, StringComparison.OrdinalIgnoreCase))
|
||||
throw new UnauthorizedAccessException("Invalid file path");
|
||||
|
||||
if (!File.Exists(fullPath))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
File.Delete(path);
|
||||
var fileInfo = new FileInfo(fullPath);
|
||||
if (fileInfo.IsReadOnly)
|
||||
fileInfo.IsReadOnly = false;
|
||||
|
||||
File.Delete(fullPath);
|
||||
}
|
||||
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw new IOException($"Failed to delete file: {fullPath}", ex);
|
||||
}
|
||||
catch (UnauthorizedAccessException ex)
|
||||
{
|
||||
throw new UnauthorizedAccessException($"No access to delete file: {fullPath}", ex);
|
||||
}
|
||||
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,9 +52,17 @@ public class MediaService : IMediaService
|
||||
}
|
||||
}
|
||||
|
||||
public Task DeleteMediaAsync(Guid fileId)
|
||||
public async Task DeleteMediaAsync(Guid mediaId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var mediaFile = await _dbContext.MediaFiles
|
||||
.FirstOrDefaultAsync(x => x.Id == mediaId)
|
||||
?? throw new KeyNotFoundException($"No media found by given id {mediaId}");
|
||||
|
||||
await _storageService.RemoveAsync(mediaFile.Url);
|
||||
|
||||
_dbContext.MediaFiles.Remove(mediaFile);
|
||||
|
||||
await _dbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public Task<Media> GetMediaByUrlAsync(string url)
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
using FirebaseAdmin.Messaging;
|
||||
using Govor.Application.Interfaces.PushNotifications;
|
||||
using Govor.Application.Interfaces.PushNotifications.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Govor.Application.Services.PushNotifications.Providers;
|
||||
|
||||
public class FirebasePushProvider : IPushNotificationProvider
|
||||
{
|
||||
private readonly ILogger<FirebasePushProvider> _logger;
|
||||
public FirebasePushProvider(ILogger<FirebasePushProvider> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public string Name => "FCM";
|
||||
|
||||
public async Task<SendPushResult> SendToTokenAsync(string token, PushMessage message)
|
||||
@@ -21,6 +28,7 @@ public class FirebasePushProvider : IPushNotificationProvider
|
||||
{
|
||||
if (IsInvalidTokenError(ex))
|
||||
{
|
||||
_logger.LogError(ex, "FCM send failed");
|
||||
return new SendPushResult(0, 1, [token]);
|
||||
}
|
||||
|
||||
@@ -63,7 +71,12 @@ public class FirebasePushProvider : IPushNotificationProvider
|
||||
{
|
||||
if (!response.Responses[i].IsSuccess)
|
||||
{
|
||||
failedTokens.Add(tokens[i]);
|
||||
var ex = response.Responses[i].Exception;
|
||||
|
||||
if (ex != null && IsInvalidTokenError(ex))
|
||||
{
|
||||
failedTokens.Add(tokens[i]); // invalid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +88,7 @@ public class FirebasePushProvider : IPushNotificationProvider
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "FCM multicast failed");
|
||||
return new SendPushResult(0, tokens.Count, tokens.ToList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Security;
|
||||
using Govor.Core.Infrastructure.Extensions;
|
||||
using Govor.Core.Models.Users;
|
||||
using Govor.Core.Repositories.PushTokens;
|
||||
@@ -62,10 +63,13 @@ public class PushTokenRepository : IPushTokenRepository
|
||||
throw new ArgumentException("Platform cannot be empty", nameof(platform));
|
||||
|
||||
var existing = await _context.UserPushTokens
|
||||
.FirstOrDefaultAsync(t => t.UserSessionId == sessionId);
|
||||
|
||||
.FirstOrDefaultAsync(t => t.UserSessionId == sessionId && t.Platform == platform);
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
if(existing.UserId != userId)
|
||||
throw new SecurityException("Token already belongs to another user");
|
||||
|
||||
// Updates
|
||||
existing.UserId = userId;
|
||||
existing.UserSessionId = sessionId;
|
||||
@@ -113,7 +117,12 @@ public class PushTokenRepository : IPushTokenRepository
|
||||
|
||||
if (toRemove.Any())
|
||||
{
|
||||
_context.UserPushTokens.RemoveRange(toRemove);
|
||||
foreach (var token in toRemove)
|
||||
{
|
||||
token.IsActive = false;
|
||||
_context.UserPushTokens.Update(token);
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,6 @@ public class UserSessionsRepository : IUserSessionsRepository
|
||||
.SetProperty(a => a.UserId, userSession.UserId)
|
||||
.SetProperty(u => u.RefreshTokenHash, userSession.RefreshTokenHash)
|
||||
.SetProperty(u => u.DeviceInfo, userSession.DeviceInfo)
|
||||
.SetProperty(u => u.CreatedAt, userSession.CreatedAt)
|
||||
.SetProperty(u => u.ExpiresAt, userSession.ExpiresAt)
|
||||
.SetProperty(u => u.IsRevoked, userSession.IsRevoked)
|
||||
);
|
||||
|
||||
@@ -84,7 +84,7 @@ public class UsersRepository : IUsersRepository
|
||||
!_context.Friendships.Any(f =>
|
||||
((f.RequesterId == currentUserId && f.AddresseeId == u.Id) ||
|
||||
(f.RequesterId == u.Id && f.AddresseeId == currentUserId)) && f.Status != FriendshipStatus.Rejected))
|
||||
.Take(10)
|
||||
.Take(7)
|
||||
.OrderBy(u => u.Username)
|
||||
.ToListOrThrowIfEmpty(new NotFoundByKeyException<(string, Guid)>((query, currentUserId), $"Users with given query for user {currentUserId} not found"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user