@@ -20,6 +20,10 @@ const languages = {
20
20
Oracle : '.sql' ,
21
21
} ;
22
22
23
+ /* Commit messages */
24
+ const readmeMsg = 'Create README - LeetHub' ;
25
+ const discussionMsg = 'Prepend discussion post - LeetHub' ;
26
+
23
27
/* Difficulty of most recenty submitted question */
24
28
let difficulty = '' ;
25
29
@@ -42,18 +46,16 @@ function findLanguage() {
42
46
}
43
47
44
48
/* Main function for uploading code to GitHub repo */
45
- const upload = ( token , hook , code , directory , filename , sha ) => {
49
+ const upload = ( token , hook , code , directory , filename , sha , msg ) => {
46
50
// To validate user, load user object from GitHub.
47
51
const URL = `https://api.github.com/repos/${ hook } /contents/${ directory } /${ filename } ` ;
48
52
49
53
/* Define Payload */
50
54
let data = {
51
- message : `working commit - Created using LeetHub` ,
55
+ message : msg ,
52
56
content : code ,
57
+ sha,
53
58
} ;
54
- if ( sha !== null ) {
55
- data . sha = sha ; // get sha for files that already exist in the gh file system.
56
- }
57
59
58
60
data = JSON . stringify ( data ) ;
59
61
@@ -99,7 +101,57 @@ const upload = (token, hook, code, directory, filename, sha) => {
99
101
xhr . send ( data ) ;
100
102
} ;
101
103
102
- function uploadGit ( code , problemName , filename ) {
104
+ /* Main function for updating code on GitHub Repo */
105
+ /* Currently only used for prepending discussion posts to README */
106
+ const update = ( token , hook , addition , directory , msg , prepend ) => {
107
+ const URL = `https://api.github.com/repos/${ hook } /contents/${ directory } /README.md` ;
108
+
109
+ /* Read from existing file on GitHub */
110
+ const xhr = new XMLHttpRequest ( ) ;
111
+ xhr . addEventListener ( 'readystatechange' , function ( ) {
112
+ if ( xhr . readyState === 4 ) {
113
+ if ( xhr . status === 200 || xhr . status === 201 ) {
114
+ const response = JSON . parse ( xhr . responseText ) ;
115
+ const existingContent = decodeURIComponent (
116
+ escape ( atob ( response . content ) ) ,
117
+ ) ;
118
+ let newContent = '' ;
119
+
120
+ /* Discussion posts prepended at top of README */
121
+ /* Future implementations may require appending to bottom of file */
122
+ if ( prepend ) {
123
+ newContent = btoa (
124
+ unescape ( encodeURIComponent ( addition + existingContent ) ) ,
125
+ ) ;
126
+ }
127
+
128
+ /* Write file with new content to GitHub */
129
+ upload (
130
+ token ,
131
+ hook ,
132
+ newContent ,
133
+ directory ,
134
+ 'README.md' ,
135
+ response . sha ,
136
+ msg ,
137
+ ) ;
138
+ }
139
+ }
140
+ } ) ;
141
+ xhr . open ( 'GET' , URL , true ) ;
142
+ xhr . setRequestHeader ( 'Authorization' , `token ${ token } ` ) ;
143
+ xhr . setRequestHeader ( 'Accept' , 'application/vnd.github.v3+json' ) ;
144
+ xhr . send ( ) ;
145
+ } ;
146
+
147
+ function uploadGit (
148
+ code ,
149
+ problemName ,
150
+ fileName ,
151
+ msg ,
152
+ action ,
153
+ prepend = true ,
154
+ ) {
103
155
/* Get necessary payload data */
104
156
chrome . storage . sync . get ( 'leethub_token' , ( t ) => {
105
157
const token = t . leethub_token ;
@@ -114,7 +166,7 @@ function uploadGit(code, problemName, filename) {
114
166
/* Get SHA, if it exists */
115
167
116
168
/* to get unique key */
117
- const filePath = problemName + filename ;
169
+ const filePath = problemName + fileName ;
118
170
chrome . storage . sync . get ( 'stats' , ( s ) => {
119
171
const { stats } = s ;
120
172
let sha = null ;
@@ -126,8 +178,29 @@ function uploadGit(code, problemName, filename) {
126
178
) {
127
179
sha = stats . sha [ filePath ] ;
128
180
}
129
- /* Upload to git. */
130
- upload ( token , hook , code , problemName , filename , sha ) ;
181
+
182
+ if ( action === 'upload' ) {
183
+ /* Upload to git. */
184
+ upload (
185
+ token ,
186
+ hook ,
187
+ code ,
188
+ problemName ,
189
+ fileName ,
190
+ sha ,
191
+ msg ,
192
+ ) ;
193
+ } else if ( action === 'update' ) {
194
+ /* Update on git */
195
+ update (
196
+ token ,
197
+ hook ,
198
+ code ,
199
+ problemName ,
200
+ msg ,
201
+ prepend ,
202
+ ) ;
203
+ }
131
204
} ) ;
132
205
}
133
206
} ) ;
@@ -168,9 +241,9 @@ function parseQuestion() {
168
241
const qbody = questionElem [ 0 ] . innerHTML ;
169
242
170
243
// Problem title.
171
- let qtitle = document . getElementsByClassName ( 'css-v3d350' ) [ 0 ] ;
244
+ let qtitle = document . getElementsByClassName ( 'css-v3d350' ) ;
172
245
if ( checkElem ( qtitle ) ) {
173
- qtitle = qtitle . innerHTML ;
246
+ qtitle = qtitle [ 0 ] . innerHTML ;
174
247
} else {
175
248
qtitle = 'unknown-problem' ;
176
249
}
@@ -192,9 +265,64 @@ function parseQuestion() {
192
265
return markdown ;
193
266
}
194
267
268
+ /* Parser function for time/space stats */
269
+ function parseStats ( ) {
270
+ const probStats = document . getElementsByClassName ( 'data__HC-i' ) ;
271
+ if ( ! checkElem ( probStats ) ) {
272
+ return null ;
273
+ }
274
+ const time = probStats [ 0 ] . textContent ;
275
+ const timePercentile = probStats [ 1 ] . textContent ;
276
+ const space = probStats [ 2 ] . textContent ;
277
+ const spacePercentile = probStats [ 3 ] . textContent ;
278
+
279
+ // Format commit message
280
+ return `Time: ${ time } (${ timePercentile } ), Space: ${ space } (${ spacePercentile } ) - LeetHub` ;
281
+ }
282
+
283
+ document . addEventListener ( 'click' , ( event ) => {
284
+ const element = event . target ;
285
+ const oldPath = window . location . pathname ;
286
+
287
+ /* Act on Post button click */
288
+ /* Complex since "New" button shares many of the same properties as "Post button */
289
+ if (
290
+ element . classList . contains ( 'icon__3Su4' ) ||
291
+ element . parentElement . classList . contains ( 'icon__3Su4' ) ||
292
+ element . parentElement . classList . contains (
293
+ 'btn-content-container__214G' ,
294
+ ) ||
295
+ element . parentElement . classList . contains ( 'header-right__2UzF' )
296
+ ) {
297
+ setTimeout ( function ( ) {
298
+ /* Only post if post button was clicked and url changed */
299
+ if (
300
+ oldPath !== window . location . pathname &&
301
+ oldPath ===
302
+ window . location . pathname . substring ( 0 , oldPath . length ) &&
303
+ ! Number . isNaN ( window . location . pathname . charAt ( oldPath . length ) )
304
+ ) {
305
+ const date = new Date ( ) ;
306
+ const currentDate = `${ date . getDate ( ) } /${ date . getMonth ( ) } /${ date . getFullYear ( ) } at ${ date . getHours ( ) } :${ date . getMinutes ( ) } ` ;
307
+ const addition = `[Discussion Post (created on ${ currentDate } )](${ window . location } ) \n` ;
308
+ const problemName = window . location . pathname . split ( '/' ) [ 2 ] ; // must be true.
309
+
310
+ uploadGit (
311
+ addition ,
312
+ problemName ,
313
+ 'README.md' ,
314
+ discussionMsg ,
315
+ 'update' ,
316
+ ) ;
317
+ }
318
+ } , 1000 ) ;
319
+ }
320
+ } ) ;
321
+
195
322
const loader = setInterval ( ( ) => {
196
323
let code = null ;
197
324
let probStatement = null ;
325
+ let probStats = null ;
198
326
199
327
const successTag = document . getElementsByClassName ( 'success__3Ai7' ) ;
200
328
if (
@@ -204,26 +332,47 @@ const loader = setInterval(() => {
204
332
) {
205
333
code = parseCode ( ) ;
206
334
probStatement = parseQuestion ( ) ;
335
+ probStats = parseStats ( ) ;
207
336
}
208
- if ( code !== null && probStatement !== null ) {
337
+ if ( code !== null && probStatement !== null && probStats !== null ) {
209
338
clearTimeout ( loader ) ;
210
339
const problemName = window . location . pathname . split ( '/' ) [ 2 ] ; // must be true.
211
340
const language = findLanguage ( ) ;
212
341
if ( language !== null ) {
213
342
uploadGit (
214
- btoa ( unescape ( encodeURIComponent ( code ) ) ) ,
343
+ btoa ( unescape ( encodeURIComponent ( probStatement ) ) ) ,
215
344
problemName ,
216
- problemName + language ,
217
- ) ; // Encode `code` to base64
345
+ 'README.md' ,
346
+ readmeMsg ,
347
+ 'upload' ,
348
+ ) ;
218
349
219
- /* @TODO : Change this setTimeout to Promise */
220
- setTimeout ( function ( ) {
221
- uploadGit (
222
- btoa ( unescape ( encodeURIComponent ( probStatement ) ) ) ,
223
- problemName ,
224
- 'README.md' ,
225
- ) ;
226
- } , 2000 ) ;
350
+ /* Only create README if not already created */
351
+ chrome . storage . sync . get ( 'stats' , ( s ) => {
352
+ const { stats } = s ;
353
+ const filePath = problemName + problemName + language ;
354
+ let sha = null ;
355
+ if (
356
+ stats !== undefined &&
357
+ stats . sha !== undefined &&
358
+ stats . sha [ filePath ] !== undefined
359
+ ) {
360
+ sha = stats . sha [ filePath ] ;
361
+ }
362
+
363
+ if ( sha === null ) {
364
+ /* @TODO : Change this setTimeout to Promise */
365
+ setTimeout ( function ( ) {
366
+ uploadGit (
367
+ btoa ( unescape ( encodeURIComponent ( code ) ) ) ,
368
+ problemName ,
369
+ problemName + language ,
370
+ probStats ,
371
+ 'upload' ,
372
+ ) ; // Encode `code` to base64
373
+ } , 2000 ) ;
374
+ }
375
+ } ) ;
227
376
}
228
377
}
229
- } , 1000 ) ;
378
+ } , 1000 ) ;
0 commit comments