1+ using Dapper ;
2+ using MapChooserSharp . Modules . McsDatabase . Entities ;
3+ using MapChooserSharp . Modules . McsDatabase . Repositories . Interfaces ;
4+ using MapChooserSharp . Modules . McsDatabase . Repositories . SqlProviders . Interfaces ;
5+ using Microsoft . Extensions . Logging ;
6+
7+ namespace MapChooserSharp . Modules . McsDatabase . Repositories ;
8+
9+ public sealed class McsUserInformationRepository
10+ : McsDatabaseRepositoryBase , IMcsUserInformationRepository
11+ {
12+ private readonly IMcsSqlQueryProvider _sqlQueryProvider ;
13+ private readonly string _connectionString ;
14+
15+ public McsUserInformationRepository ( string connectionString , McsSupportedSqlType providerType , string tableName , IServiceProvider provider )
16+ : base ( provider , tableName )
17+ {
18+ _sqlQueryProvider = CreateSqlProvider ( providerType ) ;
19+ _connectionString = connectionString ;
20+
21+ EnsureTableExists ( ) ;
22+ }
23+
24+ private void EnsureTableExists ( )
25+ {
26+ try
27+ {
28+ using var connection = _sqlQueryProvider . CreateConnection ( _connectionString ) ;
29+ connection . Open ( ) ;
30+ connection . Execute ( _sqlQueryProvider . UserInfoSqlQueries ( ) . GetEnsureTableExistsSql ( ) ) ;
31+ }
32+ catch ( Exception ex )
33+ {
34+ Plugin . Logger . LogError ( ex , "Failed to create McsUserInformation table" ) ;
35+ throw ;
36+ }
37+ Plugin . Logger . LogInformation ( "McsUserInformation table ensured" ) ;
38+ }
39+
40+ public async Task UpsertUserInformationAsync ( long steamId , McsUserInformation userInformation )
41+ {
42+ try
43+ {
44+ Logger . LogInformation ( $ "Upserting user information for SteamId { steamId } ") ;
45+
46+ using var connection = _sqlQueryProvider . CreateConnection ( _connectionString ) ;
47+ connection . Open ( ) ;
48+
49+ await connection . ExecuteAsync (
50+ _sqlQueryProvider . UserInfoSqlQueries ( ) . GetUpsertUserInfoSql ( ) ,
51+ new
52+ {
53+ SteamId = steamId ,
54+ userInformation . SessionTime ,
55+ userInformation . LastLoggedInAt ,
56+ userInformation . UserSessionStartedAt
57+ }
58+ ) ;
59+
60+ Logger . LogInformation ( $ "Successfully upserted user information for SteamId { steamId } ") ;
61+ }
62+ catch ( Exception ex )
63+ {
64+ Plugin . Logger . LogError ( ex , $ "Error upserting user information for SteamId { steamId } : { ex . Message } ") ;
65+ throw ;
66+ }
67+ }
68+
69+ public async Task IncrementUserSessionTimeAsync ( long steamId )
70+ {
71+ try
72+ {
73+ using var connection = _sqlQueryProvider . CreateConnection ( _connectionString ) ;
74+ connection . Open ( ) ;
75+
76+ var now = DateTime . UtcNow ;
77+
78+ // First try to increment existing record
79+ var rowsAffected = await connection . ExecuteAsync (
80+ _sqlQueryProvider . UserInfoSqlQueries ( ) . GetIncrementSessionTimeSql ( ) ,
81+ new { SteamId = steamId , LastLoggedInAt = now }
82+ ) ;
83+
84+ // If no rows were affected, the user doesn't exist yet, so insert a new record
85+ if ( rowsAffected == 0 )
86+ {
87+ await connection . ExecuteAsync (
88+ _sqlQueryProvider . UserInfoSqlQueries ( ) . GetUpsertUserInfoSql ( ) ,
89+ new
90+ {
91+ SteamId = steamId ,
92+ SessionTime = 1 ,
93+ LastLoggedInAt = now ,
94+ UserSessionStartedAt = now
95+ }
96+ ) ;
97+ }
98+ }
99+ catch ( Exception ex )
100+ {
101+ Plugin . Logger . LogError ( ex , $ "Error incrementing session time for SteamId { steamId } : { ex . Message } ") ;
102+ throw ;
103+ }
104+ }
105+
106+ /// <summary>
107+ /// Increments user session time with automatic reset check based on configured reset time.
108+ /// If the current time has passed the reset time since UserSessionStartedAt, the session is reset.
109+ /// </summary>
110+ /// <param name="steamId">Steam ID</param>
111+ /// <param name="resetTimeOfDay">Time of day when sessions should reset (e.g., 04:00 for 4 AM)</param>
112+ public async Task IncrementUserSessionTimeWithResetCheckAsync ( long steamId , TimeSpan resetTimeOfDay )
113+ {
114+ try
115+ {
116+ using var connection = _sqlQueryProvider . CreateConnection ( _connectionString ) ;
117+ connection . Open ( ) ;
118+
119+ var now = DateTime . UtcNow ;
120+
121+ // Get existing user information
122+ var userInfo = await connection . QueryFirstOrDefaultAsync < McsUserInformation > (
123+ _sqlQueryProvider . UserInfoSqlQueries ( ) . GetUserInfoBySteamIdSql ( ) ,
124+ new { SteamId = steamId }
125+ ) ;
126+
127+ if ( userInfo == null )
128+ {
129+ // User doesn't exist, create new record
130+ await connection . ExecuteAsync (
131+ _sqlQueryProvider . UserInfoSqlQueries ( ) . GetUpsertUserInfoSql ( ) ,
132+ new
133+ {
134+ SteamId = steamId ,
135+ SessionTime = 1 ,
136+ LastLoggedInAt = now ,
137+ UserSessionStartedAt = now
138+ }
139+ ) ;
140+ return ;
141+ }
142+
143+ // Check if we need to reset the session
144+ bool shouldReset = ShouldResetSession ( userInfo . UserSessionStartedAt , now , resetTimeOfDay ) ;
145+
146+ if ( shouldReset )
147+ {
148+ Logger . LogInformation (
149+ $ "Resetting session for SteamId { steamId } . Started at: { userInfo . UserSessionStartedAt : yyyy-MM-dd HH:mm:ss} , " +
150+ $ "Current time: { now : yyyy-MM-dd HH:mm:ss} , Reset time: { resetTimeOfDay } "
151+ ) ;
152+
153+ // Reset session time and update start time
154+ await connection . ExecuteAsync (
155+ _sqlQueryProvider . UserInfoSqlQueries ( ) . GetResetSessionTimeWithStartTimeSql ( ) ,
156+ new { SteamId = steamId , UserSessionStartedAt = now }
157+ ) ;
158+
159+ // Increment to 1 (since this is a new session)
160+ await connection . ExecuteAsync (
161+ _sqlQueryProvider . UserInfoSqlQueries ( ) . GetIncrementSessionTimeSql ( ) ,
162+ new { SteamId = steamId , LastLoggedInAt = now }
163+ ) ;
164+ }
165+ else
166+ {
167+ // Just increment normally
168+ await connection . ExecuteAsync (
169+ _sqlQueryProvider . UserInfoSqlQueries ( ) . GetIncrementSessionTimeSql ( ) ,
170+ new { SteamId = steamId , LastLoggedInAt = now }
171+ ) ;
172+ }
173+ }
174+ catch ( Exception ex )
175+ {
176+ Plugin . Logger . LogError ( ex , $ "Error incrementing session time with reset check for SteamId { steamId } : { ex . Message } ") ;
177+ throw ;
178+ }
179+ }
180+
181+ public async Task ResetUserSessionTimeAsync ( long steamId )
182+ {
183+ try
184+ {
185+ Logger . LogInformation ( $ "Resetting session time for SteamId { steamId } ") ;
186+
187+ using var connection = _sqlQueryProvider . CreateConnection ( _connectionString ) ;
188+ connection . Open ( ) ;
189+
190+ await connection . ExecuteAsync (
191+ _sqlQueryProvider . UserInfoSqlQueries ( ) . GetResetSessionTimeSql ( ) ,
192+ new { SteamId = steamId }
193+ ) ;
194+
195+ Logger . LogInformation ( $ "Successfully reset session time for SteamId { steamId } ") ;
196+ }
197+ catch ( Exception ex )
198+ {
199+ Plugin . Logger . LogError ( ex , $ "Error resetting session time for SteamId { steamId } : { ex . Message } ") ;
200+ throw ;
201+ }
202+ }
203+
204+ public async Task < McsUserInformation ? > GetUserInformationAsync ( long steamId )
205+ {
206+ try
207+ {
208+ using var connection = _sqlQueryProvider . CreateConnection ( _connectionString ) ;
209+ connection . Open ( ) ;
210+
211+ var userInfo = await connection . QueryFirstOrDefaultAsync < McsUserInformation > (
212+ _sqlQueryProvider . UserInfoSqlQueries ( ) . GetUserInfoBySteamIdSql ( ) ,
213+ new { SteamId = steamId }
214+ ) ;
215+
216+ return userInfo ;
217+ }
218+ catch ( Exception ex )
219+ {
220+ Plugin . Logger . LogError ( ex , $ "Error getting user information for SteamId { steamId } : { ex . Message } ") ;
221+ throw ;
222+ }
223+ }
224+
225+ /// <summary>
226+ /// Determines if a session should be reset based on the reset time of day.
227+ /// Returns true if the reset time has been crossed since the session started.
228+ /// </summary>
229+ /// <param name="sessionStartedAt">When the session started</param>
230+ /// <param name="currentTime">Current time</param>
231+ /// <param name="resetTimeOfDay">Time of day when reset should occur</param>
232+ /// <returns>True if session should be reset</returns>
233+ private bool ShouldResetSession ( DateTime sessionStartedAt , DateTime currentTime , TimeSpan resetTimeOfDay )
234+ {
235+ // Calculate the reset datetime for the session start date
236+ var resetDateTimeOnSessionStartDate = sessionStartedAt . Date + resetTimeOfDay ;
237+
238+ // If session started before reset time on that day, the next reset is on the same day
239+ // If session started after reset time on that day, the next reset is on the next day
240+ var nextResetTime = sessionStartedAt <= resetDateTimeOnSessionStartDate
241+ ? resetDateTimeOnSessionStartDate
242+ : resetDateTimeOnSessionStartDate . AddDays ( 1 ) ;
243+
244+ // Check if current time has passed the next reset time
245+ return currentTime >= nextResetTime ;
246+ }
247+ }
0 commit comments