1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . Linq ;
4+ using System . Threading . Tasks ;
5+ using eFormCore ;
6+ using Google . Apis . Auth . OAuth2 ;
7+ using Google . Apis . Services ;
8+ using Google . Apis . Sheets . v4 ;
9+ using Google . Apis . Sheets . v4 . Data ;
10+ using Microsoft . EntityFrameworkCore ;
11+ using Microsoft . Extensions . Logging ;
12+ using Microting . eForm . Infrastructure . Constants ;
13+ using Microting . TimePlanningBase . Infrastructure . Data ;
14+
15+ namespace BackendConfiguration . Pn . Infrastructure . Helpers ;
16+
17+ public class GoogleSheetHelper
18+ {
19+ public static async Task PushToGoogleSheet ( Core core , TimePlanningPnDbContext dbContext , ILogger logger )
20+ {
21+ var privateKeyId = Environment . GetEnvironmentVariable ( "PRIVATE_KEY_ID" ) ;
22+ var googleSheetId = dbContext . PluginConfigurationValues
23+ . Single ( x => x . Name == "TimePlanningBaseSettings:GoogleSheetId" ) . Value ;
24+ if ( string . IsNullOrEmpty ( privateKeyId ) )
25+ {
26+ return ;
27+ }
28+
29+ var applicationName = "Google Sheets API Integration" ;
30+ var sheetName = "PlanTimer" ;
31+
32+ //var core = await coreHelper.GetCore();
33+ await using var sdkDbContext = core . DbContextHelper . GetDbContext ( ) ;
34+
35+ var privateKey = Environment . GetEnvironmentVariable ( "PRIVATE_KEY" ) ; // Replace with your private key
36+ var clientEmail = Environment . GetEnvironmentVariable ( "CLIENT_EMAIL" ) ; // Replace with your client email
37+ var projectId = Environment . GetEnvironmentVariable ( "PROJECT_ID" ) ; // Replace with your project ID
38+ var clientId = Environment . GetEnvironmentVariable ( "CLIENT_ID" ) ; // Replace with your client ID
39+
40+ // Construct the JSON for the service account credentials
41+ string serviceAccountJson = $@ "
42+ {{
43+ ""type"": ""service_account"",
44+ ""project_id"": ""{ projectId } "",
45+ ""private_key_id"": ""{ privateKeyId } "",
46+ ""private_key"": ""{ privateKey } "",
47+ ""client_email"": ""{ clientEmail } "",
48+ ""client_id"": ""{ clientId } "",
49+ ""auth_uri"": ""https://accounts.google.com/o/oauth2/auth"",
50+ ""token_uri"": ""https://oauth2.googleapis.com/token"",
51+ ""auth_provider_x509_cert_url"": ""https://www.googleapis.com/oauth2/v1/certs"",
52+ ""client_x509_cert_url"": ""https://www.googleapis.com/robot/v1/metadata/x509/{ clientEmail } ""
53+ }}" ;
54+
55+ // Authenticate using the dynamically constructed JSON
56+ var credential = GoogleCredential . FromJson ( serviceAccountJson )
57+ . CreateScoped ( SheetsService . Scope . Spreadsheets ) ;
58+
59+ var service = new SheetsService ( new BaseClientService . Initializer
60+ {
61+ HttpClientInitializer = credential ,
62+ ApplicationName = applicationName
63+ } ) ;
64+
65+ try
66+ {
67+ var headerRequest = service . Spreadsheets . Values . Get ( googleSheetId , $ "{ sheetName } !A1:1") ;
68+ var headerResponse = await headerRequest . ExecuteAsync ( ) ;
69+ var existingHeaders = headerResponse . Values ? . FirstOrDefault ( ) ?? new List < object > ( ) ;
70+
71+ var assignedSites = await dbContext . AssignedSites
72+ . Where ( x => x . WorkflowState != Constants . WorkflowStates . Removed )
73+ . Select ( x => x . SiteId )
74+ . Distinct ( )
75+ . ToListAsync ( ) ;
76+
77+ var siteNames = await sdkDbContext . Sites
78+ . Where ( x => assignedSites . Contains ( x . MicrotingUid ! . Value ) )
79+ . OrderBy ( x => x . Name )
80+ . Select ( x => x . Name )
81+ . ToListAsync ( ) ;
82+
83+ var newHeaders = existingHeaders . Cast < string > ( ) . ToList ( ) ;
84+ foreach ( var siteName in siteNames )
85+ {
86+ var timerHeader = $ "{ siteName } - timer";
87+ var textHeader = $ "{ siteName } - tekst";
88+ if ( ! newHeaders . Contains ( timerHeader ) )
89+ {
90+ newHeaders . Add ( timerHeader ) ;
91+ }
92+
93+ if ( ! newHeaders . Contains ( textHeader ) )
94+ {
95+ newHeaders . Add ( textHeader ) ;
96+ }
97+ }
98+
99+ if ( ! existingHeaders . Cast < string > ( ) . SequenceEqual ( newHeaders ) )
100+ {
101+ var updateRequest = new ValueRange
102+ {
103+ Values = new List < IList < object > > { newHeaders . Cast < object > ( ) . ToList ( ) }
104+ } ;
105+
106+ var columnLetter = GetColumnLetter ( newHeaders . Count ) ;
107+ updateRequest = new ValueRange
108+ {
109+ Values = new List < IList < object > > { newHeaders . Cast < object > ( ) . ToList ( ) }
110+ } ;
111+ var updateHeaderRequest =
112+ service . Spreadsheets . Values . Update ( updateRequest , googleSheetId , $ "{ sheetName } !A1:{ columnLetter } 1") ;
113+ updateHeaderRequest . ValueInputOption =
114+ SpreadsheetsResource . ValuesResource . UpdateRequest . ValueInputOptionEnum . RAW ;
115+ await updateHeaderRequest . ExecuteAsync ( ) ;
116+
117+ logger . LogInformation ( "Headers updated successfully." ) ;
118+ }
119+
120+ AutoAdjustColumnWidths ( service , googleSheetId , sheetName , logger ) ;
121+
122+ try
123+ {
124+ // ... existing code ...
125+
126+ var sheet = service . Spreadsheets . Get ( googleSheetId ) . Execute ( ) . Sheets
127+ . FirstOrDefault ( s => s . Properties . Title == sheetName ) ;
128+ if ( sheet == null ) throw new Exception ( $ "Sheet '{ sheetName } ' not found.") ;
129+
130+ var sheetId = sheet . Properties . SheetId ;
131+
132+ // ... existing code ...
133+
134+ SetAlternatingColumnColors ( service , googleSheetId , sheetId ! . Value , newHeaders . Count , logger ) ;
135+
136+ logger . LogInformation ( "Headers are already up-to-date." ) ;
137+ }
138+ catch ( Exception ex )
139+ {
140+ logger . LogError ( $ "An error occurred: { ex . Message } ") ;
141+ }
142+
143+ logger . LogInformation ( "Headers are already up-to-date." ) ;
144+ }
145+ catch ( Exception ex )
146+ {
147+ logger . LogError ( $ "An error occurred: { ex . Message } ") ;
148+ }
149+ }
150+
151+ static void AutoAdjustColumnWidths ( SheetsService service , string spreadsheetId , string sheetName , ILogger logger )
152+ {
153+ try
154+ {
155+ var sheet = service . Spreadsheets . Get ( spreadsheetId ) . Execute ( ) . Sheets
156+ . FirstOrDefault ( s => s . Properties . Title == sheetName ) ;
157+ if ( sheet == null ) throw new Exception ( $ "Sheet '{ sheetName } ' not found.") ;
158+
159+ var sheetId = sheet . Properties . SheetId ;
160+
161+ var autoResizeRequest = new Request
162+ {
163+ AutoResizeDimensions = new AutoResizeDimensionsRequest
164+ {
165+ Dimensions = new DimensionRange
166+ {
167+ SheetId = sheetId ,
168+ Dimension = "COLUMNS" ,
169+ StartIndex = 0 , // Start from the first column
170+ EndIndex = sheet . Properties . GridProperties . ColumnCount // Auto-adjust all columns
171+ }
172+ }
173+ } ;
174+
175+ var batchRequest = new BatchUpdateSpreadsheetRequest
176+ {
177+ Requests = new List < Request > { autoResizeRequest }
178+ } ;
179+
180+ service . Spreadsheets . BatchUpdate ( batchRequest , spreadsheetId ) . Execute ( ) ;
181+
182+ logger . LogInformation ( "Column widths auto-adjusted successfully." ) ;
183+ }
184+ catch ( Exception ex )
185+ {
186+ logger . LogError ( $ "An error occurred while auto-adjusting column widths: { ex . Message } ") ;
187+ }
188+ }
189+
190+ private static string GetColumnLetter ( int columnIndex )
191+ {
192+ string columnLetter = "" ;
193+ while ( columnIndex > 0 )
194+ {
195+ int modulo = ( columnIndex - 1 ) % 26 ;
196+ columnLetter = Convert . ToChar ( 65 + modulo ) + columnLetter ;
197+ columnIndex = ( columnIndex - modulo ) / 26 ;
198+ }
199+
200+ return columnLetter ;
201+ }
202+
203+ static void SetAlternatingColumnColors ( SheetsService service , string spreadsheetId , int sheetId , int columnCount ,
204+ ILogger logger )
205+ {
206+ var requests = new List < Request > ( ) ;
207+
208+ for ( int i = 3 ; i < columnCount ; i += 2 ) // Start from column D (index 3) and increment by 2
209+ {
210+ var color1 = new Color { Red = 1 , Green = 1 , Blue = 1 } ;
211+ var color2 = new Color { Red = 0.9f , Green = 0.9f , Blue = 0.9f } ;
212+
213+ var color = ( ( i / 2 ) % 2 == 0 ) ? color1 : color2 ;
214+
215+ var updateCellsRequest1 = new Request
216+ {
217+ RepeatCell = new RepeatCellRequest
218+ {
219+ Range = new GridRange
220+ {
221+ SheetId = sheetId ,
222+ StartColumnIndex = i ,
223+ EndColumnIndex = i + 1
224+ } ,
225+ Cell = new CellData
226+ {
227+ UserEnteredFormat = new CellFormat
228+ {
229+ BackgroundColor = color
230+ }
231+ } ,
232+ Fields = "userEnteredFormat.backgroundColor"
233+ }
234+ } ;
235+
236+ var updateCellsRequest2 = new Request
237+ {
238+ RepeatCell = new RepeatCellRequest
239+ {
240+ Range = new GridRange
241+ {
242+ SheetId = sheetId ,
243+ StartColumnIndex = i + 1 ,
244+ EndColumnIndex = i + 2
245+ } ,
246+ Cell = new CellData
247+ {
248+ UserEnteredFormat = new CellFormat
249+ {
250+ BackgroundColor = color
251+ }
252+ } ,
253+ Fields = "userEnteredFormat.backgroundColor"
254+ }
255+ } ;
256+
257+ requests . Add ( updateCellsRequest1 ) ;
258+ requests . Add ( updateCellsRequest2 ) ;
259+ }
260+
261+ var batchUpdateRequest = new BatchUpdateSpreadsheetRequest
262+ {
263+ Requests = requests
264+ } ;
265+
266+ service . Spreadsheets . BatchUpdate ( batchUpdateRequest , spreadsheetId ) . Execute ( ) ;
267+
268+ logger . LogInformation ( "Alternating column colors set successfully." ) ;
269+ }
270+ }
0 commit comments