1- using System . Text . Json ;
21using Microsoft . AspNetCore . Mvc ;
3- using Microsoft . EntityFrameworkCore ;
4- using Microsoft . Extensions . Caching . Distributed ;
5- using Microsoft . Extensions . Caching . Memory ;
6- using OpenBioCardServer . Data ;
7- using OpenBioCardServer . Interfaces ;
82using OpenBioCardServer . Models . DTOs . Classic ;
93using OpenBioCardServer . Services ;
10- using OpenBioCardServer . Utilities . Mappers ;
114
125namespace OpenBioCardServer . Controllers . Classic ;
136
147[ Route ( "classic/user" ) ]
158[ ApiController ]
169public class ClassicUserController : ControllerBase
1710{
18- private readonly AppDbContext _context ;
1911 private readonly ClassicAuthService _authService ;
20- private readonly ICacheService _cacheService ;
12+ private readonly ClassicProfileService _profileService ;
2113 private readonly ILogger < ClassicUserController > _logger ;
2214
2315 public ClassicUserController (
24- AppDbContext context ,
2516 ClassicAuthService authService ,
26- ICacheService cacheService ,
17+ ClassicProfileService profileService ,
2718 ILogger < ClassicUserController > logger )
2819 {
29- _context = context ;
3020 _authService = authService ;
31- _cacheService = cacheService ;
21+ _profileService = profileService ;
3222 _logger = logger ;
3323 }
3424
35-
36- // 生成统一的 Cache Key
37- private static string GetProfileCacheKey ( string username ) =>
38- $ "Classic:Profile:{ username . Trim ( ) . ToLowerInvariant ( ) } ";
39-
4025 /// <summary>
4126 /// Get user profile (public endpoint)
4227 /// </summary>
4328 [ HttpGet ( "{username}" ) ]
4429 public async Task < IActionResult > GetProfile ( string username )
4530 {
46- string cacheKey = GetProfileCacheKey ( username ) ;
47-
4831 try
4932 {
50- var profileDto = await _cacheService . GetOrCreateAsync ( cacheKey , async ( ) =>
51- {
52- var profile = await _context . Profiles
53- . AsNoTracking ( )
54- . AsSplitQuery ( )
55- . Include ( p => p . Contacts )
56- . Include ( p => p . SocialLinks )
57- . Include ( p => p . Projects )
58- . Include ( p => p . WorkExperiences )
59- . Include ( p => p . SchoolExperiences )
60- . Include ( p => p . Gallery )
61- . FirstOrDefaultAsync ( p => p . Username == username ) ;
62- return profile == null ? null : ClassicMapper . ToClassicProfile ( profile ) ;
63- } ) ;
33+ var profileDto = await _profileService . GetProfileAsync ( username ) ;
6434
6535 if ( profileDto == null )
6636 {
6737 return NotFound ( new { error = "User not found" } ) ;
6838 }
39+
6940 return Ok ( profileDto ) ;
7041 }
7142 catch ( Exception ex )
@@ -75,125 +46,45 @@ public async Task<IActionResult> GetProfile(string username)
7546 }
7647 }
7748
78-
7949 /// <summary>
8050 /// Update user profile (requires authentication)
8151 /// </summary>
8252 [ HttpPost ( "{username}" ) ]
8353 public async Task < IActionResult > UpdateProfile ( string username , [ FromBody ] ClassicProfile request )
8454 {
85- using var transaction = await _context . Database . BeginTransactionAsync ( ) ;
55+ var token = Request . Headers [ "Authorization" ] . FirstOrDefault ( ) ? . Replace ( "Bearer " , "" ) ;
8656
87- try
57+ if ( string . IsNullOrEmpty ( token ) )
8858 {
89- // Extract token from Authorization header
90- var token = Request . Headers [ "Authorization" ] . FirstOrDefault ( ) ? . Replace ( "Bearer " , "" ) ;
91-
92- if ( string . IsNullOrEmpty ( token ) )
93- {
94- return Unauthorized ( new { error = "Missing authentication token" } ) ;
95- }
96-
97- var ( isValid , account ) = await _authService . ValidateTokenAsync ( token ) ;
98-
99- if ( ! isValid || account == null )
100- {
101- return Unauthorized ( new { error = "Invalid token" } ) ;
102- }
59+ return Unauthorized ( new { error = "Missing authentication token" } ) ;
60+ }
10361
104- if ( account . UserName != username )
105- {
106- return Unauthorized ( new { error = "Token does not match username" } ) ;
107- }
62+ var ( isValid , account ) = await _authService . ValidateTokenAsync ( token ) ;
10863
109- var profile = await _context . Profiles
110- . AsTracking ( )
111- . FirstOrDefaultAsync ( p => p . Username == username ) ;
64+ if ( ! isValid || account == null )
65+ {
66+ return Unauthorized ( new { error = "Invalid token" } ) ;
67+ }
11268
113- if ( profile == null )
114- {
115- return NotFound ( new { error = "Profile not found " } ) ;
116- }
69+ if ( account . UserName != username )
70+ {
71+ return Unauthorized ( new { error = "Token does not match username " } ) ;
72+ }
11773
118- // Update basic profile fields
119- ClassicMapper . UpdateProfileFromClassic ( profile , request ) ;
120-
121- // Clear all existing collections using ExecuteDeleteAsync
122- await _context . ContactItems
123- . Where ( c => c . ProfileId == profile . Id )
124- . ExecuteDeleteAsync ( ) ;
74+ try
75+ {
76+ var success = await _profileService . UpdateProfileAsync ( username , request ) ;
12577
126- await _context . SocialLinkItems
127- . Where ( s => s . ProfileId == profile . Id )
128- . ExecuteDeleteAsync ( ) ;
129-
130- await _context . ProjectItems
131- . Where ( p => p . ProfileId == profile . Id )
132- . ExecuteDeleteAsync ( ) ;
133-
134- await _context . WorkExperienceItems
135- . Where ( w => w . ProfileId == profile . Id )
136- . ExecuteDeleteAsync ( ) ;
137-
138- await _context . SchoolExperienceItems
139- . Where ( s => s . ProfileId == profile . Id )
140- . ExecuteDeleteAsync ( ) ;
141-
142- await _context . GalleryItems
143- . Where ( g => g . ProfileId == profile . Id )
144- . ExecuteDeleteAsync ( ) ;
145-
146- // Add new collections from request
147- if ( request . Contacts ? . Any ( ) == true )
148- {
149- var contacts = ClassicMapper . ToContactEntities ( request . Contacts , profile . Id ) ;
150- await _context . ContactItems . AddRangeAsync ( contacts ) ;
151- }
152-
153- if ( request . SocialLinks ? . Any ( ) == true )
154- {
155- var socialLinks = ClassicMapper . ToSocialLinkEntities ( request . SocialLinks , profile . Id ) ;
156- await _context . SocialLinkItems . AddRangeAsync ( socialLinks ) ;
157- }
158-
159- if ( request . Projects ? . Any ( ) == true )
160- {
161- var projects = ClassicMapper . ToProjectEntities ( request . Projects , profile . Id ) ;
162- await _context . ProjectItems . AddRangeAsync ( projects ) ;
163- }
164-
165- if ( request . WorkExperiences ? . Any ( ) == true )
78+ if ( ! success )
16679 {
167- var workExperiences = ClassicMapper . ToWorkExperienceEntities ( request . WorkExperiences , profile . Id ) ;
168- await _context . WorkExperienceItems . AddRangeAsync ( workExperiences ) ;
169- }
170-
171- if ( request . SchoolExperiences ? . Any ( ) == true )
172- {
173- var schoolExperiences = ClassicMapper . ToSchoolExperienceEntities ( request . SchoolExperiences , profile . Id ) ;
174- await _context . SchoolExperienceItems . AddRangeAsync ( schoolExperiences ) ;
175- }
176-
177- if ( request . Gallery ? . Any ( ) == true )
178- {
179- var gallery = ClassicMapper . ToGalleryEntities ( request . Gallery , profile . Id ) ;
180- await _context . GalleryItems . AddRangeAsync ( gallery ) ;
80+ return NotFound ( new { error = "Profile not found" } ) ;
18181 }
18282
183- await _context . SaveChangesAsync ( ) ;
184- await transaction . CommitAsync ( ) ;
185-
186- // 清除缓存
187- await _cacheService . RemoveAsync ( GetProfileCacheKey ( username ) ) ;
188-
189- _logger . LogInformation ( "Profile updated for user: {Username}" , username ) ;
190-
19183 return Ok ( new { success = true } ) ;
19284 }
193- catch ( Exception ex )
85+ catch ( Exception )
19486 {
195- await transaction . RollbackAsync ( ) ;
196- _logger . LogError ( ex , "Error updating profile for user: {Username}" , username ) ;
87+ // Exception is already logged in the service
19788 return StatusCode ( 500 , new { error = "Profile update failed" } ) ;
19889 }
19990 }
0 commit comments