From 619518e7bfdfeea86f39ba5a63f233a7800e965f Mon Sep 17 00:00:00 2001 From: xiaolipro <2357729423@qq.com> Date: Fri, 20 Mar 2026 15:15:43 +0800 Subject: [PATCH] init --- .gitignore | 13 ++ NuGet.Config | 7 + README.md | 180 ++++++++++++++++++ SimpleAdmin.sln | 44 +++++ src/Program.cs | 28 +++ src/Properties/launchSettings.json | 34 ++++ src/SimpleAdmin.Api.csproj | 18 ++ src/SimpleAdmin.Api.http | 6 + src/SimpleAdminApiModule.cs | 89 +++++++++ src/SimpleJwtService.cs | 28 +++ src/appsettings.Development.json | 9 + src/appsettings.json | 8 + ...-4a5c-83e5-70e164b15f2f_20251224143133.jpg | Bin 0 -> 8147 bytes ...-4a5c-83e5-70e164b15f2f_20251225174451.jpg | Bin 0 -> 9326 bytes 14 files changed, 464 insertions(+) create mode 100644 .gitignore create mode 100644 NuGet.Config create mode 100644 README.md create mode 100644 SimpleAdmin.sln create mode 100644 src/Program.cs create mode 100644 src/Properties/launchSettings.json create mode 100644 src/SimpleAdmin.Api.csproj create mode 100644 src/SimpleAdmin.Api.http create mode 100644 src/SimpleAdminApiModule.cs create mode 100644 src/SimpleJwtService.cs create mode 100644 src/appsettings.Development.json create mode 100644 src/appsettings.json create mode 100644 src/uploads/avatars/08de4226-3fd4-4a5c-83e5-70e164b15f2f_20251224143133.jpg create mode 100644 src/uploads/avatars/08de4226-3fd4-4a5c-83e5-70e164b15f2f_20251225174451.jpg diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..783d1c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +bin/ +obj/ +/packages/ +riderModule.iml +/_ReSharper.Caches/ + +.idea/ +/.vs +/Fake.sln.DotSettings.user + +Logs/ + +node_modules/ \ No newline at end of file diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 0000000..69486f2 --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..8af4aa8 --- /dev/null +++ b/README.md @@ -0,0 +1,180 @@ +# SimpleAdmin API + +基于 Fake 框架的简单管理系统后端 API。 + +## 技术栈 + +- **.NET 8.0** - 最新的 .NET 平台 +- **Fake Framework** - 模块化应用框架 +- **Entity Framework Core** - ORM 框架 +- **SQL Server** - 数据库 +- **JWT** - 身份认证 +- **Swagger** - API 文档 + +## 功能特性 + +- ✅ 模块化架构 +- ✅ 自动 API 生成(ApplicationService 自动转换为 Controller) +- ✅ RBAC 权限管理 +- ✅ JWT 认证 +- ✅ Swagger 文档 +- ✅ 依赖注入 +- ✅ 工作单元 +- ✅ 审计日志 + +## 开始使用 + +### 前置要求 + +- .NET 8.0 SDK +- SQL Server (LocalDB 或完整版) + +### 配置数据库 + +修改 `appsettings.json` 中的连接字符串: + +```json +{ + "ConnectionStrings": { + "Default": "Server=(localdb)\\mssqllocaldb;Database=SimpleAdminDb;Trusted_Connection=true;MultipleActiveResultSets=true" + } +} +``` + +### 数据库迁移 + +```bash +# 添加迁移 +dotnet ef migrations add InitialCreate --project ../modules/rbac/Fake.Rbac.Infrastructure + +# 更新数据库 +dotnet ef database update --project ../modules/rbac/Fake.Rbac.Infrastructure +``` + +### 运行项目 + +```bash +dotnet run +``` + +访问 http://localhost:5000 查看 Swagger 文档。 + +## 默认账号 + +系统会自动创建默认管理员账号: + +- 账号:admin +- 密码:123456 +- 角色:超级管理员 + +**⚠️ 重要:请在生产环境中立即修改默认密码!** + +## API 端点 + +### 认证 API + +- `POST /api/auth/login` - 用户登录 +- `GET /api/auth/current` - 获取当前用户信息 +- `PUT /api/auth/password` - 修改密码 + +### 用户管理 API + +- `GET /api/rbac/user/list` - 获取用户列表 +- `GET /api/rbac/user/{id}` - 获取用户详情 +- `POST /api/rbac/user` - 创建用户 +- `PUT /api/rbac/user/{id}` - 更新用户 +- `DELETE /api/rbac/user/{id}` - 删除用户 +- `PUT /api/rbac/user/{id}/roles` - 分配角色 +- `GET /api/rbac/user/{id}/permissions` - 获取用户权限 + +### 角色管理 API + +- `GET /api/rbac/role/list` - 获取角色列表 +- `GET /api/rbac/role/all` - 获取所有角色 +- `GET /api/rbac/role/{id}` - 获取角色详情 +- `POST /api/rbac/role` - 创建角色 +- `PUT /api/rbac/role/{id}` - 更新角色 +- `DELETE /api/rbac/role/{id}` - 删除角色 +- `PUT /api/rbac/role/{id}/permissions` - 分配权限 + +### 菜单管理 API + +- `GET /api/rbac/menu/tree` - 获取菜单树 +- `GET /api/rbac/menu/user/{userId}` - 获取用户菜单 +- `GET /api/rbac/menu/{id}` - 获取菜单详情 +- `POST /api/rbac/menu` - 创建菜单 +- `PUT /api/rbac/menu/{id}` - 更新菜单 +- `DELETE /api/rbac/menu/{id}` - 删除菜单 + +### 权限管理 API + +- `GET /api/rbac/permission/all` - 获取所有权限 +- `GET /api/rbac/permission/tree` - 获取权限树 + +## 项目结构 + +``` +SimpleAdmin.Api/ +├── Controllers/ # 控制器(手动创建的) +├── Program.cs # 程序入口 +├── SimpleAdminApiModule.cs # 主模块配置 +├── appsettings.json # 配置文件 +└── README.md +``` + +## Fake 框架特性 + +### 自动 API 生成 + +所有继承自 `ApplicationService` 的服务会自动生成对应的 API 端点,无需手动创建 Controller。 + +### 模块化 + +通过 `[DependsOn]` 特性声明模块依赖: + +```csharp +[DependsOn( + typeof(FakeAspNetCoreModule), + typeof(FakeRbacApplicationModule) +)] +public class SimpleAdminApiModule : FakeModule +{ + // ... +} +``` + +### 依赖注入 + +框架自动注册服务,支持: +- `ITransientDependency` - 瞬时 +- `IScopedDependency` - 作用域 +- `ISingletonDependency` - 单例 + +### 工作单元 + +应用服务方法自动包装在工作单元中,支持事务管理。 + +## JWT 配置 + +JWT 配置在 `appsettings.json` 中: + +```json +{ + "JwtSettings": { + "SecretKey": "your-secret-key-here", + "ExpiryInMinutes": 60 + } +} +``` + +## CORS 配置 + +默认允许的前端地址: +- http://localhost:3000 +- http://localhost:5173 + +可在 `SimpleAdminApiModule.cs` 中修改。 + +## 许可证 + +MIT diff --git a/SimpleAdmin.sln b/SimpleAdmin.sln new file mode 100644 index 0000000..97bdf8b --- /dev/null +++ b/SimpleAdmin.sln @@ -0,0 +1,44 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleAdmin.Api", "src\SimpleAdmin.Api.csproj", "{F6418A25-D1B2-48E1-BDCA-80CC5262BB18}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "items", "items", "{BE5132AD-C95E-4CB7-AFBD-0D4838AFD48C}" + ProjectSection(SolutionItems) = preProject + NuGet.Config = NuGet.Config + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Debug|x64.ActiveCfg = Debug|Any CPU + {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Debug|x64.Build.0 = Debug|Any CPU + {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Debug|x86.ActiveCfg = Debug|Any CPU + {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Debug|x86.Build.0 = Debug|Any CPU + {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Release|Any CPU.Build.0 = Release|Any CPU + {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Release|x64.ActiveCfg = Release|Any CPU + {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Release|x64.Build.0 = Release|Any CPU + {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Release|x86.ActiveCfg = Release|Any CPU + {F6418A25-D1B2-48E1-BDCA-80CC5262BB18}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {F6418A25-D1B2-48E1-BDCA-80CC5262BB18} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B} + EndGlobalSection +EndGlobal diff --git a/src/Program.cs b/src/Program.cs new file mode 100644 index 0000000..386aaa7 --- /dev/null +++ b/src/Program.cs @@ -0,0 +1,28 @@ +using Serilog; +using SimpleAdmin.Api; + +var builder = WebApplication.CreateSlimBuilder(args); +builder.Configuration.AddConsul("idwms/common", source => source.ReloadOnChange = true); +builder.Configuration.AddConsul("idwms/admin", source => source.ReloadOnChange = true); + +Log.Logger = new LoggerConfiguration() + .ReadFrom.Configuration(builder.Configuration) + .CreateLogger(); + +try +{ + builder.WebHost.UseUrls(builder.Configuration.GetSection("App:Urls").Get() ?? []); + builder.Host.UseAutofac().UseSerilog(); + builder.Services.AddApplication(); + var app = builder.Build(); + app.InitializeApplication(); + await app.RunAsync(); +} +catch (Exception ex) +{ + Log.Fatal(ex, "G"); +} +finally +{ + Log.CloseAndFlush(); +} \ No newline at end of file diff --git a/src/Properties/launchSettings.json b/src/Properties/launchSettings.json new file mode 100644 index 0000000..786b6f7 --- /dev/null +++ b/src/Properties/launchSettings.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:22279", + "sslPort": 44353 + } + }, + "profiles": { + "dev": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "", + "applicationUrl": "http://localhost:5281", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "staging": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "launchUrl": "", + "applicationUrl": "http://localhost:5281", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Staging", + "ASPNETCORE_PATHBASE": "/admin" + } + } + } +} diff --git a/src/SimpleAdmin.Api.csproj b/src/SimpleAdmin.Api.csproj new file mode 100644 index 0000000..6169fe9 --- /dev/null +++ b/src/SimpleAdmin.Api.csproj @@ -0,0 +1,18 @@ + + + + net8.0 + enable + enable + e3d506cf-f5ce-4ba5-bc8e-ab2c179f3034 + + + + + + + + + + + \ No newline at end of file diff --git a/src/SimpleAdmin.Api.http b/src/SimpleAdmin.Api.http new file mode 100644 index 0000000..6da01ba --- /dev/null +++ b/src/SimpleAdmin.Api.http @@ -0,0 +1,6 @@ +@SimpleAdmin.Api_HostAddress = http://localhost:5281 + +GET {{SimpleAdmin.Api_HostAddress}}/weatherforecast/ +Accept: application/json + +### diff --git a/src/SimpleAdminApiModule.cs b/src/SimpleAdminApiModule.cs new file mode 100644 index 0000000..444199a --- /dev/null +++ b/src/SimpleAdminApiModule.cs @@ -0,0 +1,89 @@ +using Fake.AspNetCore; +using Fake.Autofac; +using Fake.Modularity; +using Fake.Rbac.Application; +using Fake.Rbac.Infrastructure; +using Fake.AspNetCore.Auditing; +using Fake.AspNetCore.Mvc; +using Fake.Serilog; +using Microsoft.AspNetCore.HttpOverrides; + +namespace SimpleAdmin.Api; + +[DependsOn( + typeof(FakeAutofacModule), + typeof(FakeRbacApplicationModule), + typeof(FakeRbacInfrastructureModule), + typeof(FakeSerilogModule) +)] +public class SimpleAdminApiModule : FakeModule +{ + private const string DefaultCorsPolicyName = "default"; + + public override void ConfigureServices(ServiceConfigurationContext context) + { + var services = context.Services; + var configuration = context.Services.GetConfiguration(); + + // 配置动态 API - 扫描 RBAC 应用服务 + services.Configure(options => + { + options.ApplicationServices2Controller(settings => + { + settings.RootPath = "rbac"; + }); + }); + + services.AddFakeAspNetCoreAuditing(); + + // 添加 Fake Swagger 支持 + services.AddFakeSwaggerGen(addSecurity: true); + + services.AddCors(options => + { + options.AddPolicy(DefaultCorsPolicyName, builder => + { + builder.WithOrigins(configuration.GetSection("App:CorsOrigins").Get() ?? []) + .AllowAnyHeader() + .AllowAnyMethod() + .AllowCredentials(); + }); + }); + + services.Configure(options => + { + options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; + //新增如下两行 + options.KnownNetworks.Clear(); + options.KnownProxies.Clear(); + }); + } + + public override void ConfigureApplication(ApplicationConfigureContext context) + { + var app = context.GetWebApplication(); + + // 虚拟路由-网关适配 + app.UsePathBase(app.Configuration["ASPNETCORE_PATHBASE"]); + + // Swagger + app.UseFakeSwagger(); + // 异常处理 + app.UseFakeExceptionHandling(); + // CORS + app.UseCors("Default"); + + // 静态文件服务(用于头像等上传文件) + app.UseStaticFiles(); + + // 路由 - 必须在认证和授权之前 + app.UseRouting(); + + // 认证和授权 + app.UseAuthentication(); + app.UseAuthorization(); + + // 端点映射 + app.MapControllers(); + } +} \ No newline at end of file diff --git a/src/SimpleJwtService.cs b/src/SimpleJwtService.cs new file mode 100644 index 0000000..0f2149f --- /dev/null +++ b/src/SimpleJwtService.cs @@ -0,0 +1,28 @@ +using System.Security.Claims; +using Fake.AspNetCore.Authentication; +using Fake.DependencyInjection; +using Fake.Rbac.Application.Jwt; +using Fake.Rbac.Application.Services; +using Fake.Rbac.Infrastructure; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Options; + +namespace SimpleAdmin.Api; + +/// +/// 自定义simple-admin auth jwt service +/// +[Dependency(Replace = true)] +public class SimpleJwtService(IOptions jwtOptions, IUserService userService, FakeRbacDbContext rbacDbContext) + : JwtService(jwtOptions, userService) +{ + public override async Task> GenerateClaimsByUserIdAsync(Guid userId, + CancellationToken cancellationToken) + { + var claims = await base.GenerateClaimsByUserIdAsync(userId, cancellationToken); + var mapId = await rbacDbContext.Database.SqlQuery($"select userid as value from user where id = {userId}") + .FirstAsync(cancellationToken); + claims.Add(new Claim("mapId", mapId.ToString())); + return claims; + } +} \ No newline at end of file diff --git a/src/appsettings.Development.json b/src/appsettings.Development.json new file mode 100644 index 0000000..62539e8 --- /dev/null +++ b/src/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning", + "Microsoft.EntityFrameworkCore": "Information" + } + } +} \ No newline at end of file diff --git a/src/appsettings.json b/src/appsettings.json new file mode 100644 index 0000000..01a9d8c --- /dev/null +++ b/src/appsettings.json @@ -0,0 +1,8 @@ +{ + "UseLocalConfigs": false, + "Consul": { + "Address": "https://consul.nanafa.com", + // 用户机密 + "Token": "" + } +} \ No newline at end of file diff --git a/src/uploads/avatars/08de4226-3fd4-4a5c-83e5-70e164b15f2f_20251224143133.jpg b/src/uploads/avatars/08de4226-3fd4-4a5c-83e5-70e164b15f2f_20251224143133.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7525f915570b44120e43acadd8e7ad6ab33bbde5 GIT binary patch literal 8147 zcmbVxbyOVR@@K=~8YH*{g1bYI!8Jf|7%VV2!Civ{2`+&Icb5RcB_Ti)phGrw@=@e$JxhK;E9TYvI2mF1OP~g4R~BfCR3J`HG8F{ zp`iRy{vQJ}27nM09sqE3@^I5ql%X>)gwUa{{_BjtHgl-E%isNf5k%a}>A%qdV1o0% z`23&Ln3h)VP=v!VqFK5j21g{TgTTZ#|H8I^vBke|z+dd`;o^btN&Ji5bhKmfCmD5BRo6+TLf|kv=9~<1kwTA5FSnljWu9}z`)=7A>tt zh-37R4blA#AbuwW`)RE8Idm(;6flifCu0OgdV#90t}!ZNCP3!1IPqO zAOfVvUZes{h`x}OlUGnw zQdZH{(bdyOlmKdJWo=_?XYcOe>E-R?>lgMeJR&mceROilht#x>pVBi53X6(MO3TVC z>c2EJHZ`}jwsrUP{^*1C4-Ae^OioSD%+AfPt#52@ZNq=>?4F#SonKsDUEkay0ib`; zLG=G(^dEc(5PXnPP(Uc?fB7IGdm|c%00s3KFB+k=Cc3#R5j|fB2C+<1e%*IW27ayM zrxtEwSR~H{))-IzQu>F{{~e*w|1U=WL+F3_JT3t505rseprW9mA*KZ#4Fl^578WKZ z7BL<^&J$8%GBQ$P5)uk(Mp_C=1}YK~Iu1GpCT3PPR&rWS9!?e>Miy2UBy@CiEDS6n zEG!}x3K9yI|7Ure2XH`0h|2~<0DyrVb1uJ)rvf2~XIe$CEvMQ)@$sPo)`w1A6EnUC z+C`!VdKS&2_5f^}!%TC$rYiQx8Q!Nol5oV`QjN=?p0nINy#!B&;;7PodIWrrc~c-` zkW$p{lRd~2i6XN-=BOaiJS-kNCXLP%$gAI)8y}v!aq7Q(7ci0b2zX*Xr1G9frjy-R zv?kus(GLGY*)c@CA4cjL`#KR}E^%Tq*B=*C#F>6GQ}QgNfl8B(lq67s_KSl%BV zJ`|8hegKyG#V9lc73D@ZUd^j;*>prg6)wl47Q9c8^TY6=xxc1z>F}yw%Hj@CGnnR9NR4I1Z1fk>7Mbn;KWX@*je2;nX@mrow8n5<8VOMrUm-=U?4&8LKS&8 zWAB?`7XU7RlyUM!$Z?D7Yx<7npjEiAiUH0>jf0j0S@BK5jnR~v_2Nxc2`iXpOaih z5Ay_4KMNMLBW&gwQUm8O&>9L~?c#|D{`|d68`1q+okr0G<0eyZY8mnf}iKR7DLGl9X(Jq)1_rah@R#-8J@9^0aX$fKb4Dfs5$ zZh!E9(520ccX8D#dS`i}>-1Dk9Uo-({1y-`c1@yJ;3{s7W+EJ{h@V>x|0!~>rXp8b zpHPW)W_RHo#hZNd0W{A3iR4ojSgP)p&M57H0X%z5eU(8biUc4{c~X|j30f# zGeH!Hfe|*=p>h7i&fBp^F|JMi$wBT5Kr$I_alZEl3-^xA?5dHWWow|Y zfxrK?xx**uDYdB;)=0PqY$SYVC0Au^eE-K0=h*z7DZ@v_$?fPsAw$PkXoh*tnTh;~ zfuq%C^_^cP8^+4|w#B@jlYDx^CjI?q;9f+e`gIshrX3$tySXKnPujKKkVnC_VeOQ6 zLC{F&#Oj;^bvmKa$IpSahztiw7u|(<(?vpzNcnp-+_B7Hk8o+BChigwnz^+k9_|7w zrK5`OntXne{qBgk%`@22qLj!c(LS;}TOHes_&Z*{565IGGG$gTe`lZzf9y>0bt7m| zjqk}=dos1UG`z0Z0q4iD<3V3}p3%}W+xw+#18$Af=tn?hzfn->AdgV!2RDTi1D$2C z$Zf`Y2Syy}JAw65j_L1ENp2gDAmGih*nx-j5Kh6bWWQ#JrCy*Am81~w>?`TNCRO>DDRkJ zRtG3fA0@5xDWbf@;*s0M4{})Q@OQv{Nb$CXUnR@meU;p^N!T*u+Ed{?+H7v6(d~W9 z&PsKnmErV5q@hMy{A_5eVVq}|lDYLrQ=pyp*}w+1J*y=nrm0N4JuAI47i;2um5b!p zRJk+-Gt{?Uv%9`1TKg#v{>+>9zgm=5&nsf$1vRYx&ZqXtzMr|0QRVr!Wwe9WKlO*)ZaX2rI4FR~u! zTc+ML5;(uvhH_l;Ke;oSp7_F@BM-RNfJ0BTQP<~t%n>iQr8v9V&lHONQuqbI4cUz9?#s<2w-Vm68Dw)? zoxXa9GImlCFZZS5CHTH=>VTDnY;KpT4sb>U&v3J^CzU6-{K*o7#R?p1Gtf z%D(Z}+&K5W?AliJ;Pb{w$9yD9aElypcj#v8i;- zjw7T&tP}T&)eCguF!rjU1dUIwnoG9xn}m-*?>GI4&(C0(z68qr52voTIxT!3)-TO@ zpDA5bbK~_w*dwWDxo__GkUXCzXrygu+d9rKzAbXJ=#PAkL*<6Y?yoRewJ|omO}?HZ z?B-4sv2hFx1Sz25?!o z?kIF?RBqvFF>avx28-?C*5KSiCN>*0t z`Kn%1=JBb&k7v6B<(_hX_t%ul)>LVf^P| z9`|IoseS0nFlv62X{VnnW=^Xtgfsw@+8KJ<6=~hAgz)xqa+6%m^*67?Hgi5{8);V# z=JJL^gdI|8G)nE8^&g&|ygXx7j5l;l=3jVY?t8Bcj`K@vU5(;w@R!cByChgqcxvMw zWjNu4KaBoa5KedOAp`GPUABNp@ZDU&k8$!FiRZR~W~fizM5{Mql}ZbBsu zbJ@J9*<-5|P5Iy?DlHc6T2NS0($R9ulFE{e=o>1U)VX_^*qyei^}vt&W4_f}bfP9j z$QbA7;~fvG2b*EWxPnZ6Cw6^s{?B&24O&BAMVihB`T{HCIQ%H~FNWUb`nfImg&3!f zvwrw=8~8%slj)!wzE14hK&Gy#VD~Lf;>iYzc1PU~Bnw_=I#jhsq264j$U&00)MuVU zyqxp;z3zKZP8YZ7cI`cGVa*qze5x<~xvc~o_O9DsHd&Y@>Jr5^o?5_rg)2+ub}o6o z7|G+*wefIJZ}!`OL%OI%$~vey+Vt9AH%IIJaDujEUim^BsG#56O**E%q{chv_E=F9 zLOV36duP-w+M1N4Kay$U*!Y_(=9w;ysDk6q9pdDatd<<;3uIZs-&Ikl)%y;fh6Ebm+?mxCTr3t@1*s;m2~*op;)nCdcBTVDvt?Q1huCe!+WR#sJvOMUn(zR_S&R9x|l~Gua9a8T>30>0r7>2 z{*OSCaeVH^H!25~Q~9!8!d^-T0U#jf+L$OBZpS%S?|3fRkfvuIiYD3EcmFa=adkwV zAUIjqK%d%e7@ao#Gg?F26tl%VJjxR{yf#9)L@p>Dy#@Ab#<_6zT4G<%zZ!zlp~xK; zWY9E`$an7^GOOb*AEt(TOuw=-56<*=aHn2ZvUKYzI2f2!e6tFIZI~EC-reeUR?OEb z+lVRC9e0kR=+W=pR{VBrYIdsK;UF&lohB?LvJo~Div!9yGkfCm^~&&TY93cxfMrzV z64Kio4Q<25!Erskea|(Q`1Z#APP`bHU-M;2?I`D3OPmzI@|~G%*ZqgPrlJ%7DVN4) zruvK%6JaJHy@mF~w(K6u=uhYjvXXtZcU1eply~iSBd33_TG7yJnnR9;5pQ-Lvzq-4!Pa$d{M}{R z#)(EX84S*YBkZ<_(t8Fnaa4DXyW3^p{EW|3}Zx`qUMf6P?}*?hV1 zF*weRt}V&jh%gYi-db^rmqluJCEGbCzjvVTQ9V(wlKRqUP;jvIBmDjZ0)8Sc%L(hH z92%jq&;k+*-!0-z!9#gx1Y3&(l%~y_eJ-$#?D~xv9)Sure?oMWKwdMm$ZWe;?}{4j zjL)p|hX>o7d(^yqQQG4A(d(VNXj36G9n_9CNU8^Vf-NpmSS5;PK^N)Z7{O|F>(~`> z*QDem-dBq7+#Z1`U2ld1e8R-1?;?G~-BbF&6m!}s(=R_V{u*gK#=We__gGjkktaQp z`hrnvb`46zU$rL_2tU58rh-%nH_ZUsVz#p!BaZ;GmW#xm%nn_sm%(P@!6v`QXuvu9 z!N`lZkr|iGq?ZvXmTBV`_|Lx@4dkpsbIV~Hx|}3c3}0c!0bu8KpKVevznXM5fMDz6 zu)-r?YngR-W_-R(G9~cai9W|aD&6Rb8YOS2{DoU7`}O%%O%Ue2_v%ipa8t7*<$VP+ z>PPT?ZT}w!$W?DfjNQ6edT@^XO?Pf;VCO^QaK6A@;Z#qli5pCQQsb$8ovB0?DXCRe zwfU=B*8Vfsv)s|v1LNxLeE8ZkN(O46Z2Q?tN=wRep);p63^K>gP7{-wT3A4f6FJg# z*8*RDzhF*v_Ub)~i!$>|?}`I=c+^5E)h{d7vPw?@`cH7Qnjc_LMi1du#iaI$th`Kl zJr~B2>Sc=IiAccxEW>mW><)TXUN>GL83`@CR|GrMHU$dJ86A-29P)|pq_!Ytzr^QO zzi_WDFgNOarG5p*arvtv>M9MV$kIl1b1Iu*jWk@~?)r#?vV2(>FGhT`j3KED1dj8h zVbmpgHW9Qs+wDE#$jb7)s8Lcjbz6UPYDk1M@A~>kQ%3j3D{o@qSsN?&k3hJ0##J|au`kou=dk1-_vL+};>X>sm9(fn zIcmypHYaTKXiq0=Pht1?r582*Q(;EwBFY4_EWu6p5$4IfSr63hR4GT0Thr`vhr{

`vE`UOpSbVRsz=UysGU+f*3M5ZAFVYZifO?W)+YH7OfvHKOr z>sQ%msxvq=vFdpEA8 zE=LjYj0!C+2+bB+p|YF;Ru-J8qTRD}l*y-p|7BV6r&X-!UY!gXd!i7+o}7*h`|P@K zYNZNn?sR^op=3XsM#H#ISyKiZx}sZdgH$?Wl4LfW`sLs-`lJdku9vYb?8}9Jwv=t$ zup9$i^~BFFi#&?S9o+Z!v^qtTc%QGKp_-T19*-p@Z~l6Y z9@T$uPZG|ba)o%fT+cj%lP!K-)O^j!@cKdz45_U;m?5ihWy{%!FDzk`fft;Y1g9Np z68pTu7JjQT;@)XMkSGuFksD}yPZN>PBQ8s=SXSzf1xxoS?Ed(zBdu?$eDmS9zh(Xb*?*xH`+W%~)9pu_f`rDmywB)O(W1r4>z;h%n2&(r zfasySzPyB*-m?kOU#5m6BHwMG!RUU4RdUB>%1-;3F~CNNYsR6YBd6n``0r^2(FAP-H34(v@eKpO{3QrZw^VGR+Y0YIFs2m2YVOO7W;o3y7AsGf?(+}d& zS=`LiEn|Ij#%^$8(hcmcvSw0ox4>P4^{#<}EN_+Q?}DHEHF7+~iBC5cbU_ocOubQ-g@aM^wumLxF{7MA@|J!K;0 z3uKFI?5?fPP5;)lPes)huxNx^QxaykAro`Z9-&+3jIyM|vnLd6rYr=1 zO0ZV6CrGeOY9`xCiIOrSSK51*TjxNYSTj7_&@}wfx)HdRsiE+qWjVhR9H}BDl^dW} z(v9~{LR`_elTQ0#(EcDv2k)fLh~#8GBVz?8W>8hG5HZotcahJu0O*i?4zcW1lOsN! zWy>u(C)>uN;eKB(4nEwZh;3bpuEWM6{g5wF zmPAg8EAxfHNqYohNNClAU(I0eWxu3U{d|sRG>ENtEIc5g&AwsmM(gBCgKjFHixj6Q zp&0FWAvMkvy{wqMPoAd@bb1II4^NWbeanXK!L*7`uD$Q7aQ5fwe)r`<^RgTM1hK`! z-F9$u`ei_}m&VTms$6Z2c%h{3KEB>ntfn;n*mct9o*PN?EsgxMHHFl^k{>R#V1nix zPCOdP*EEw`p;GOGPYPpi-4lM>)`pUG9jHxmCwEgFPY5rW?b>#>tC9)RX2@RYPq*F~ zFisw3D5uB1zCYM|=r3)rC-S0&+TO+K;tDj22}^& zyL2_fO+#C<^)8MWIh5z|X)dNz;?6~Pr?&LPo!3*h`YP8Qa)o3D@CXH&505cn>kd(E zwXSbQ6My*9`RS{!mrpyo-F(04xJ3Vr$1dngMT2kOT=+}XQT|Y?TT$kx!e=;G=WM z|5JOCLby~@kEU;njD6vSsL8dHr16Fz_Rh>{LkOp3?@P@t7>XA-6)m~kQaAZc?nhdP zO~!KJX$f>ZR$Fv&bF_7mY_K8Vi5q^Wfl+&&@>wo(#`~|o^ZslYV`k1~886yM+M)O% z{gCwx;B?F!egiMKf=*|Fjw==pm#cbPPKajP+CYM zZhphZS4Q6|5TCZ%%O3&Q=XG|7{ouCNGK|04Ud@|T9!$5oaigb7m0&LW=khkg{I2@^ zvpRvMo?^PFsMwbtPh*MudM|J2O-2h?qSA7?1VhqCHLl7#6KtI*LAKNi4oufJb0+-CfWtav5L zE`jCkJyYqHx$QVs@TW)@8#6njs3Unx^~f5 PM8(9y5EZGnk8}SEcnK7+ literal 0 HcmV?d00001 diff --git a/src/uploads/avatars/08de4226-3fd4-4a5c-83e5-70e164b15f2f_20251225174451.jpg b/src/uploads/avatars/08de4226-3fd4-4a5c-83e5-70e164b15f2f_20251225174451.jpg new file mode 100644 index 0000000000000000000000000000000000000000..12e3f5c497f50b38f38e6e6b36c3977ff44079b3 GIT binary patch literal 9326 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 literal 0 HcmV?d00001