codequiry-cli 1.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,96 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const os = require('os');
6
+ const archiver = require('archiver');
7
+
8
+ const EXCLUDE_PATTERNS = [
9
+ '.git',
10
+ 'node_modules',
11
+ '.DS_Store',
12
+ '__pycache__',
13
+ '.idea',
14
+ '.vscode',
15
+ '*.pyc',
16
+ '.env',
17
+ 'Thumbs.db',
18
+ ];
19
+
20
+ function shouldExclude(entryName) {
21
+ const basename = path.basename(entryName);
22
+ return EXCLUDE_PATTERNS.some((p) => {
23
+ if (p.startsWith('*')) return basename.endsWith(p.slice(1));
24
+ return basename === p;
25
+ });
26
+ }
27
+
28
+ function zipDirectory(dirPath, outputPath) {
29
+ return new Promise((resolve, reject) => {
30
+ const output = fs.createWriteStream(outputPath);
31
+ const archive = archiver('zip', { zlib: { level: 6 } });
32
+
33
+ output.on('close', () => resolve(outputPath));
34
+ archive.on('error', reject);
35
+
36
+ archive.pipe(output);
37
+ archive.directory(dirPath, false, (entry) => {
38
+ if (shouldExclude(entry.name)) return false;
39
+ return entry;
40
+ });
41
+ archive.finalize();
42
+ });
43
+ }
44
+
45
+ async function prepareUploads(inputPath) {
46
+ const stat = fs.statSync(inputPath);
47
+ const tmpDir = os.tmpdir();
48
+ const zipFiles = [];
49
+
50
+ if (!stat.isDirectory()) {
51
+ // It's already a file (presumably a zip)
52
+ if (inputPath.endsWith('.zip')) {
53
+ return [inputPath];
54
+ }
55
+ throw new Error('Input must be a .zip file or a directory.');
56
+ }
57
+
58
+ // Check if the directory has subdirectories (each = a submission)
59
+ const entries = fs.readdirSync(inputPath);
60
+ const subdirs = entries.filter((e) => {
61
+ const fullPath = path.join(inputPath, e);
62
+ return fs.statSync(fullPath).isDirectory() && !shouldExclude(e);
63
+ });
64
+
65
+ if (subdirs.length > 1) {
66
+ // Multiple subdirectories = batch mode (each subdir is a submission)
67
+ for (const subdir of subdirs) {
68
+ const subdirPath = path.join(inputPath, subdir);
69
+ const zipPath = path.join(tmpDir, `codequiry_${subdir}_${Date.now()}.zip`);
70
+ await zipDirectory(subdirPath, zipPath);
71
+ zipFiles.push(zipPath);
72
+ }
73
+ } else {
74
+ // Single directory = one submission
75
+ const dirName = path.basename(inputPath);
76
+ const zipPath = path.join(tmpDir, `codequiry_${dirName}_${Date.now()}.zip`);
77
+ await zipDirectory(inputPath, zipPath);
78
+ zipFiles.push(zipPath);
79
+ }
80
+
81
+ return zipFiles;
82
+ }
83
+
84
+ function cleanupTempFiles(filePaths) {
85
+ filePaths.forEach((fp) => {
86
+ try {
87
+ if (fp.includes(os.tmpdir()) && fs.existsSync(fp)) {
88
+ fs.unlinkSync(fp);
89
+ }
90
+ } catch {
91
+ // ignore cleanup errors
92
+ }
93
+ });
94
+ }
95
+
96
+ module.exports = { zipDirectory, prepareUploads, cleanupTempFiles };
package/src/auth.js DELETED
@@ -1,47 +0,0 @@
1
- import inquirer from 'inquirer';
2
- import axios from 'axios';
3
- import fs from 'fs';
4
- import { manageChecks } from './check.js';
5
- import { API_KEY_FILE } from './const.js';
6
- import { getApiKey } from './util.js';
7
-
8
- export async function authenticate() {
9
- let apiKey = getApiKey();
10
-
11
- if (!apiKey) {
12
- const answers = await inquirer.prompt([
13
- {
14
- type: 'input',
15
- name: 'apiKey',
16
- message: 'Enter your API key:'
17
- }
18
- ]);
19
-
20
- apiKey = answers.apiKey;
21
- }
22
-
23
- if (apiKey) {
24
- try {
25
- const response = await axios.post('https://codequiry.com/api/v1/account', null, {
26
- headers: {
27
- 'Accept': '*/*',
28
- 'apikey': apiKey,
29
- }
30
- });
31
-
32
- if (response.status === 200) {
33
- fs.writeFileSync(API_KEY_FILE, JSON.stringify({ apiKey }));
34
- console.log(`Hello, ${response.data.user}!\nYour email is ${response.data.email}.`);
35
-
36
- manageChecks();
37
- } else {
38
- console.log('Invalid API key. Please re-enter the key.');
39
- }
40
- } catch (error) {
41
- console.error('Authentication failed:', error.response.data);
42
- if (fs.existsSync(API_KEY_FILE)) {
43
- fs.unlinkSync(API_KEY_FILE);
44
- }
45
- }
46
- }
47
- }
package/src/check.js DELETED
@@ -1,444 +0,0 @@
1
- import inquirer from 'inquirer';
2
- import axios from 'axios';
3
- import fs from 'fs';
4
- import FormData from 'form-data';
5
- import { API_KEY_FILE, validLanguageIds } from './const.js'
6
- import { isValidNumber, getApiKey, getZipFiles } from './util.js'
7
-
8
-
9
- export async function manageChecks() {
10
- try {
11
- const { apiKey } = JSON.parse(fs.readFileSync(API_KEY_FILE, 'utf8'));
12
-
13
- const action = await inquirer.prompt([
14
- {
15
- type: 'list',
16
- name: 'action',
17
- message: 'Choose an action:',
18
- choices: ['Create Check', 'Start Check', 'Upload to Check']
19
- }
20
- ]);
21
-
22
- switch (action.action) {
23
- case 'Create Check':
24
- await _createCheck(apiKey);
25
- break;
26
- case 'Start Check':
27
- await _startCheck(apiKey);
28
- break;
29
- case 'Upload to Check':
30
- await _uploadToCheck(apiKey);
31
- break;
32
- default:
33
- console.log('Invalid action.');
34
- }
35
- } catch (error) {
36
- if (error.message.includes('User force closed the prompt')) {
37
- } else {
38
- console.error('An unexpected error occurred:', error);
39
- }
40
- }
41
- }
42
-
43
- export function createCheck() {
44
- try {
45
- const apiKey = getApiKey();
46
- if (!apiKey) {
47
- console.log('Please authenticate first.');
48
- return;
49
- }
50
- _createCheck(apiKey);
51
- } catch (error) {
52
- if (error.message.includes('User force closed the prompt')) {
53
- } else {
54
- console.error('An unexpected error occurred:', error);
55
- }
56
- }
57
- }
58
-
59
- async function _createCheck(apiKey) {
60
- try {
61
- const answers = await inquirer.prompt([
62
- {
63
- type: 'input',
64
- name: 'language',
65
- message: 'Enter the programming language:'
66
- },
67
- {
68
- type: 'input',
69
- name: 'name',
70
- message: 'Enter the your name:'
71
- },
72
- ]);
73
-
74
- if (answers.language === '' || !isValidNumber(answers.language)) {
75
- console.log(validLanguageIds);
76
- return;
77
- }
78
- if (answers.name === '' || answers.name.length < 4) {
79
- console.log('Please enter name. And name must be at least 4 characters.');
80
- return;
81
- }
82
-
83
- try {
84
- const response = await axios.post('https://codequiry.com/api/v1/check/create', null, {
85
- params: {
86
- name: answers.name,
87
- language: answers.language,
88
- },
89
- headers: {
90
- 'Accept': '*/*',
91
- 'apikey': apiKey,
92
- }
93
- });
94
-
95
- if (response.status === 201) {
96
- console.log('Check created successfully:', response.data);
97
- } else {
98
- console.log('Failed to create check.');
99
- }
100
- } catch (error) {
101
- console.error('Error Creating Check:', error.response.data);
102
- }
103
- } catch (error) {
104
- if (error.message.includes('User force closed the prompt')) {
105
- } else {
106
- console.error('An unexpected error occurred:', error);
107
- }
108
- }
109
- }
110
-
111
- export function startCheck() {
112
- try {
113
- const apiKey = getApiKey();
114
- if (!apiKey) {
115
- console.log('Please authenticate first.');
116
- return;
117
- }
118
- _startCheck(apiKey);
119
- } catch (error) {
120
- if (error.message.includes('User force closed the prompt')) {
121
- } else {
122
- console.error('An unexpected error occurred:', error);
123
- }
124
- }
125
- }
126
-
127
- async function _startCheck(apiKey) {
128
- try {
129
- const answers = await inquirer.prompt([
130
- {
131
- type: 'input',
132
- name: 'checkId',
133
- message: 'Enter the check ID:'
134
- },
135
- {
136
- type: 'list',
137
- name: 'addintionalCheck',
138
- message: 'Select the additional check type:',
139
- choices: ['webcheck', 'dbcheck', 'group_similarity_only']
140
- }
141
- ]);
142
-
143
- if (answers.checkId === '' || !isValidNumber(answers.checkId)) {
144
- console.log('Please enter check ID. And check ID must be a number.');
145
- return;
146
- }
147
- if (answers.addintionalCheck === '') {
148
- console.log('Please select additional check type.');
149
- return;
150
- }
151
-
152
- let params = {};
153
- if (answers.addintionalCheck === 'webcheck') {
154
- params = { 'check_id': answers.checkId, 'webcheck': 1 };
155
- } else if (answers.addintionalCheck === 'dbcheck') {
156
- params = { 'check_id': answers.checkId, 'dbcheck': 1 };
157
- } else if (answers.addintionalCheck === 'group_similarity_only') {
158
- params = { 'check_id': answers.checkId };
159
- }
160
- try {
161
- const response = await axios.post(`https://codequiry.com/api/v1/check/start`, null, {
162
- params: {
163
- ...params
164
- },
165
- headers: {
166
- 'apikey': apiKey,
167
- }
168
- });
169
-
170
- if (response.status === 200 && !response.data.hasOwnProperty('error')) {
171
- console.log('Check started successfully.\n', response.data);
172
- } else {
173
- console.log('Failed to start check.', response.data);
174
- }
175
- } catch (error) {
176
- console.error('Error starting check:', error.response.data);
177
- }
178
- } catch (error) {
179
- if (error.message.includes('User force closed the prompt')) {
180
- } else {
181
- console.error('An unexpected error occurred:', error);
182
- }
183
- }
184
-
185
- }
186
-
187
- export function uploadToCheck() {
188
- try {
189
- const apiKey = getApiKey();
190
- if (!apiKey) {
191
- console.log('Please authenticate first.');
192
- return;
193
- }
194
- _uploadToCheck(apiKey);
195
- } catch (error) {
196
- if (error.message.includes('User force closed the prompt')) {
197
- } else {
198
- console.error('An unexpected error occurred:', error);
199
- }
200
- }
201
-
202
- }
203
-
204
- async function _uploadToCheck(apiKey) {
205
- try {
206
- const answers = await inquirer.prompt([
207
- {
208
- type: 'input',
209
- name: 'checkId',
210
- message: 'Enter the check ID:'
211
- }
212
- ]);
213
-
214
- if (answers.checkId === '' || !isValidNumber(answers.checkId)) {
215
- console.log('Please enter check ID. And check ID must be a number.');
216
- return;
217
- }
218
-
219
- const files = getZipFiles();
220
-
221
- if (answers.checkId === '') {
222
- console.log('Please enter check ID.');
223
- return;
224
- }
225
- if (files.length === 0) {
226
- console.log('No ZIP files found in uploads folder.\nPlease copy files in upload folder and try again.');
227
- return;
228
- }
229
-
230
-
231
- files.forEach(async (file, index) => {
232
- try {
233
- const form = new FormData();
234
- form.append('file', fs.createReadStream(`./uploads/${file}`));
235
- form.append('check_id', answers.checkId);
236
- const response = await axios.post('https://codequiry.com/api/v1/check/upload', form, {
237
- headers: {
238
- apikey: apiKey,
239
- }
240
- });
241
-
242
- if (response.status === 200) {
243
- console.log('File uploaded successfully.', response.data);
244
- } else {
245
- console.log('Failed to upload file.');
246
- }
247
- } catch (error) {
248
- console.error('Error uploading file:', error.message);
249
- }
250
- });
251
- } catch (error) {
252
- if (error.message.includes('User force closed the prompt')) {
253
- } else {
254
- console.error('An unexpected error occurred:', error);
255
- }
256
- }
257
- }
258
-
259
- export async function retriveCheck() {
260
- try {
261
- const apiKey = getApiKey();
262
- if (!apiKey) {
263
- console.log('Please authenticate first.');
264
- return;
265
- }
266
-
267
- try {
268
- const response = await axios.post(`https://codequiry.com/api/v1/checks`, null, {
269
- headers: {
270
- 'Accept': '*/*',
271
- 'apikey': apiKey,
272
- }
273
- });
274
-
275
- if (response.status === 200) {
276
- console.log('Retrive Checks successfully.\n', response.data);
277
- } else {
278
- console.log('Failed to retrive check.', response.data);
279
- }
280
- } catch (error) {
281
- console.error('Error retriving checks:', error.response.data);
282
- }
283
- } catch (error) {
284
- if (error.message.includes('User force closed the prompt')) {
285
- } else {
286
- console.error('An unexpected error occurred:', error);
287
- }
288
- }
289
-
290
- }
291
-
292
- export async function checkStatus() {
293
- try {
294
- const apiKey = getApiKey();
295
- if (!apiKey) {
296
- console.log('Please authenticate first.');
297
- return;
298
- }
299
- const answers = await inquirer.prompt([
300
- {
301
- type: 'input',
302
- name: 'checkId',
303
- message: 'Enter the check ID:'
304
- }
305
- ]);
306
- if (answers.checkId === '' || !isValidNumber(answers.checkId)) {
307
- console.log('Please enter check ID. And check ID must be a number.');
308
- return;
309
- }
310
-
311
- let params = { check_id: answers.checkId };
312
-
313
- try {
314
- const response = await axios.post(`https://codequiry.com/api/v1/check/get`, null, {
315
- params: {
316
- ...params
317
- },
318
- headers: {
319
- 'Accept': '*/*',
320
- 'apikey': apiKey,
321
- }
322
- });
323
-
324
- if (response.status === 200) {
325
- console.log('Check status successfully.\n', response.data);
326
- } else {
327
- console.log('Failed to check status.', response.data);
328
- }
329
- } catch (error) {
330
- console.error('Error check status:', error.response.data);
331
- }
332
- } catch (error) {
333
- if (error.message.includes('User force closed the prompt')) {
334
- } else {
335
- console.error('An unexpected error occurred:', error);
336
- }
337
- }
338
- }
339
-
340
- export async function resultOverview() {
341
- try {
342
- const apiKey = getApiKey();
343
- if (!apiKey) {
344
- console.log('Please authenticate first.');
345
- return;
346
- }
347
- const answers = await inquirer.prompt([
348
- {
349
- type: 'input',
350
- name: 'checkId',
351
- message: 'Enter the check ID:'
352
- }
353
- ]);
354
-
355
- if (answers.checkId === '' || !isValidNumber(answers.checkId)) {
356
- console.log('Please enter check ID. And check ID must be a number.');
357
- return;
358
- }
359
-
360
- let params = { check_id: answers.checkId };
361
-
362
- try {
363
- const response = await axios.post(`https://codequiry.com/api/v1/check/overview`, null, {
364
- params: {
365
- ...params
366
- },
367
- headers: {
368
- 'Accept': '*/*',
369
- 'apikey': apiKey,
370
- }
371
- });
372
-
373
- if (response.status === 200) {
374
- console.log('Result Overview.\n', response.data);
375
- } else {
376
- console.log('Failed to check result overview.', response.data);
377
- }
378
- } catch (error) {
379
- console.error('Error check result overview:', error.response.data);
380
- }
381
- } catch (error) {
382
- if (error.message.includes('User force closed the prompt')) {
383
- } else {
384
- console.error('An unexpected error occurred:', error);
385
- }
386
- }
387
- }
388
-
389
- export async function detailedResult() {
390
- try {
391
- const apiKey = getApiKey();
392
- if (!apiKey) {
393
- console.log('Please authenticate first.');
394
- return;
395
- }
396
- const answers = await inquirer.prompt([
397
- {
398
- type: 'input',
399
- name: 'checkId',
400
- message: 'Enter the check ID:'
401
- },
402
- {
403
- type: 'input',
404
- name: 'submissionId',
405
- message: 'Enter the submission ID:'
406
- }
407
- ]);
408
- if (answers.checkId === '' || !isValidNumber(answers.checkId)) {
409
- console.log('Please enter check ID. And check ID must be a number.');
410
- return;
411
- }
412
- if (answers.submissionId === '' || !isValidNumber(answers.submissionId)) {
413
- console.log('Please enter submission ID. And submission ID must be a number.');
414
- return;
415
- }
416
-
417
- let params = { check_id: answers.checkId, submission_id: answers.submissionId };
418
-
419
- try {
420
- const response = await axios.post(`https://codequiry.com/api/v1/check/overview`, null, {
421
- params: {
422
- ...params
423
- },
424
- headers: {
425
- 'Accept': '*/*',
426
- 'apikey': apiKey,
427
- }
428
- });
429
-
430
- if (response.status === 200) {
431
- console.log('Detailed Result.\n', response.data);
432
- } else {
433
- console.log('Failed to detailed result.', response.data);
434
- }
435
- } catch (error) {
436
- console.error('Error get detailed result:', error.response.data);
437
- }
438
- } catch (error) {
439
- if (error.message.includes('User force closed the prompt')) {
440
- } else {
441
- console.error('An unexpected error occurred:', error);
442
- }
443
- }
444
- }
package/src/const.js DELETED
@@ -1,56 +0,0 @@
1
- export const API_KEY_FILE = './apikey.json';
2
- export const validLanguageIds = {
3
- "error": "Invalid programming language, must be a valid language ID",
4
- "available_languages": [
5
- { id: 13, language: 'Java (.java)' },
6
- { id: 14, language: 'Python (.py)' },
7
- { id: 16, language: 'C (.c/.h)' },
8
- { id: 17, language: 'C/C++ (.cc/.c/.h/.cpp/.hpp)' },
9
- { id: 18, language: 'C# (.cs)' },
10
- { id: 20, language: 'Perl (.pl/.sh)' },
11
- { id: 21, language: 'PHP (.php)' },
12
- { id: 22, language: 'SQL (.sql)' },
13
- { id: 23, language: 'VB (.vb/.bas)' },
14
- { id: 24, language: 'XML (.xml)' },
15
- { id: 28, language: 'Haskell (.hs/.lhs)' },
16
- { id: 29, language: 'Pascal (.pas/.inc)' },
17
- { id: 30, language: 'Go (.go)' },
18
- { id: 31, language: 'Matlab (.m)' },
19
- { id: 32, language: 'Lisp (.el)' },
20
- { id: 33, language: 'Ruby (.rb)' },
21
- { id: 34, language: 'Assembly (.asm/.s)' },
22
- { id: 38, language: 'HTML Javascript (.html/.htm/.xhtml)' },
23
- { id: 39, language: 'Javascript (.js/.ts)' },
24
- { id: 40, language: 'HTML (.html/.htm/.xhtml)' },
25
- { id: 41, language: 'Plain text (.txt)' },
26
- { id: 42, language: 'Text file by char (.txt)' },
27
- { id: 43, language: 'Swift (.swift)' },
28
- { id: 44, language: 'Kotlin (.kt/.kts)' },
29
- { id: 45, language: 'Yacc (.y,.yy,.ypp,.yxx)' },
30
- { id: 46, language: 'Lex (.l,.ll)' },
31
- { id: 47, language: 'Elixir (.ex, .exs)' },
32
- { id: 48, language: 'Python Jupyter Notebook (.ipynb)' },
33
- { id: 49, language: 'Dart (.dart)' },
34
- { id: 50, language: 'Shell (.sh/.bash)' },
35
- { id: 51, language: 'Rust (.rs)' },
36
- { id: 52, language: 'Scala (.scala)' },
37
- { id: 53, language: 'R (.r)' },
38
- { id: 54, language: 'Objective-C (.m, .mm)' },
39
- { id: 55, language: 'TypeScript (.ts, .tsx)' },
40
- { id: 56, language: 'Markdown (.md)' },
41
- { id: 57, language: 'Julia (.jl)' },
42
- { id: 58, language: 'Groovy (.groovy)' },
43
- { id: 59, language: 'Sass/SCSS (.scss, .sass)' },
44
- { id: 60, language: 'CoffeeScript (.coffee)' },
45
- { id: 61, language: 'Lua (.lua)' },
46
- { id: 62, language: 'Erlang (.erl, .hrl)' },
47
- { id: 63, language: 'F# (.fs, .fsi, .fsx)' },
48
- { id: 64, language: 'Fortran (.f90, .f95)' },
49
- { id: 65, language: 'Haxe (.hx)' },
50
- { id: 66, language: 'Scheme (.scm, .ss)' },
51
- { id: 67, language: 'Tcl (.tcl)' },
52
- { id: 68, language: 'Ada (.adb, .ads)' },
53
- { id: 69, language: 'COBOL (.cob, .cbl)' },
54
- { id: 70, language: 'VHDL (.vhd, .vhdl)' }
55
- ]
56
- }
package/src/util.js DELETED
@@ -1,26 +0,0 @@
1
- import fs from 'fs';
2
- import { API_KEY_FILE } from './const.js';
3
- import path from 'path';
4
-
5
- export function getApiKey() {
6
- if (fs.existsSync(API_KEY_FILE)) {
7
- return JSON.parse(fs.readFileSync(API_KEY_FILE, 'utf8')).apiKey;
8
- } else {
9
- return null;
10
- }
11
- }
12
-
13
- export function isValidNumber(value) {
14
- return !isNaN(value) && typeof Number(value) === 'number';
15
- };
16
-
17
- export function getZipFiles() {
18
- try {
19
- const files = fs.readdirSync('./uploads/');
20
- const zipFiles = files.filter(file => path.extname(file).toLowerCase() === '.zip');
21
- return zipFiles;
22
- } catch (error) {
23
- console.error('Error reading directory:', error);
24
- return [];
25
- }
26
- };
package/uploads/.gitkeep DELETED
File without changes