Spaces:
Sleeping
Sleeping
Tristan Yu commited on
Commit ·
d8b2bc7
1
Parent(s): f129e6c
Align top-level backend routes to support image-only content (week>=3), remove legacy content-required validations
Browse files- apg5611-2b2170947124.json +13 -0
- deploy/backend +1 -1
- deploy/frontend +1 -1
- public/manifest.json +9 -1
- server/routes/auth.js +12 -13
apg5611-2b2170947124.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"type": "service_account",
|
| 3 |
+
"project_id": "apg5611",
|
| 4 |
+
"private_key_id": "2b2170947124eb920335bdcb80fbecc371e7cdec",
|
| 5 |
+
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCqdwDBYHh2cBbe\nX8L33mR5/ng1RkULZ8YRh5X30POcjQE9KffnpXe1R7inOCtZPlkCW5AuawySeciX\nU9X/Px1Nkn7eNdAy2Im+RTJZw+9VqPufgHo7cp/ACBLUutrUmyTTFJJ3in07ciMz\nB07j1FqdlFD0d6yOsCNmJR2MaiYCaH/VHDJ1YOfCUrqfkQEz+92C6of9PfHsUVoV\nSlyb/4TC5FGtjVQ6fc2cs4wjXAbPLS8HVd8DjDQRmYYAAhL29BZCLoIgZQZh62lJ\nL6DMJH6rAn3OHpR/HX8JfiItt9iMuVN7v5ZrXc1fwizyt8dV3uxhLl5nAUsHrNAH\nrSu/LHGBAgMBAAECggEAFO0+EP9UWonhLNSJvV82a4mTXUrun/tR5AYGoaErvvzK\neaVE01HLc9xFrXWmULLoP3NZLHGk3fiIaRd4LnkjkknZPFNT52IQ6uRYzY9Ruuzf\nUxH1L4YfWXZERYxY3//Z0fX1EyrTu/ADpTiQ9UQ1CaJTG+fzLaMu/VOyIHJJj0Ls\neQbeBDbDCFbqbJTEE+144SNb8TI9Dg29npDWgiDptO7hzGZVsgVYmO6LTQNkv/mT\nhoxbDJMD1jDcSguEeNzxHL6jcTOfgcSbc94VFZv8YoGsvKUgU3bbW+YYKKDwq4ui\nJsOHVnN7zXmL90Fbb4kvi++eQ+h7VjZ0P22GmK3jLwKBgQDhpT8dn1DQs2jxexxs\ns4VFgUAVIPoXaiWeyceSzK3TWM5bKPxrUAK0Kwl23oA2TkBJw+NmP0VUSaDG2PUA\nGu/P6pVE1Kvm+HQUDEqAIvbRih+Qc8Ey2WvoCKOnL19H8UhuTpYYiQhL46f+4yVU\n7ybjxHzfbez+2BjghUaQXlx0OwKBgQDBZXOyBQTVjjkJ3MboIci9oQYZ0Cb0MWuu\nr1QbgZqIMp9VkXblDfUvbA9KwUPOfL8n21K6qoiA9DGfs9MZTn0HXcuaXx1guVgc\niYOepGdAxN0pAOTeJvf2mHDW5U0dzfnSeFg/Hylplwq3v4FOZsNDXK8ijcMCErmD\n3o5Q+pABcwKBgGW8B1Tnu5wdB7e4dfxchD3uJGJiV9+ur/+DokOBnO2pIIDhXc1U\naaOps76wWsYhScL4WtKCvFNgTujYcL33ZyAq99nsuQSOCGfxkrVrDjUzPT/3sKeo\nd4pKOt7p8N+S3cE+FVZCkkcFAX1eFDrTCImw0Uw7V5se+zhfXo1AvhZ5AoGBAIgs\nqVRWGFtOs3bwT9Yvw6tScHtIh8U17z6nEa/0iB0SmAKmVHNgap4jlnjqsJX6XJbx\n5cSuQ0OZrj9nXWLaU0sWjkB6bLMojpQ5d8YCuPlwJNG0YXLTOZIXMI0AFFbCLAA4\n4NpBVOWWhuNvIttTnHYYEvFfpEoXaS0jTk5Sv4dlAoGBAJCwW+dKPIYcFfMNU9ec\nMYqJuhe7EugYA6JBHXsAFaiyNj+MJBev4XuWShxyn8ApBxKcS1NdXF3pUjQEXSi/\ni8WtYUIFkh7J915/OWeWMqZE+hpHD3nLfb3dMoYnbrAJGpHeG0Thxa4RO2sMmfcz\n2jrpHf83SdfsMriOfhCvF8Ux\n-----END PRIVATE KEY-----\n",
|
| 6 |
+
"client_email": "apg5603-group-discussion-docs@apg5611.iam.gserviceaccount.com",
|
| 7 |
+
"client_id": "111100204656070048644",
|
| 8 |
+
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
| 9 |
+
"token_uri": "https://oauth2.googleapis.com/token",
|
| 10 |
+
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
| 11 |
+
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/apg5603-group-discussion-docs%40apg5611.iam.gserviceaccount.com",
|
| 12 |
+
"universe_domain": "googleapis.com"
|
| 13 |
+
}
|
deploy/backend
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
Subproject commit
|
|
|
|
| 1 |
+
Subproject commit 92347b29ca49a6324b7a4d4eba3b00633dd638a6
|
deploy/frontend
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
Subproject commit
|
|
|
|
| 1 |
+
Subproject commit f129e6c37924dddd9d0db79052bbcb30ff5b3484
|
public/manifest.json
CHANGED
|
@@ -2,11 +2,19 @@
|
|
| 2 |
"short_name": "Transcreation Sandbox",
|
| 3 |
"name": "Transcreation Sandbox - Translation Practice Tool",
|
| 4 |
"icons": [
|
|
|
|
| 5 |
{ "src": "/favicon-192.png", "sizes": "192x192", "type": "image/png" },
|
| 6 |
{ "src": "/favicon-512.png", "sizes": "512x512", "type": "image/png" }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
],
|
| 8 |
"start_url": ".",
|
| 9 |
"display": "standalone",
|
| 10 |
"theme_color": "#000000",
|
| 11 |
"background_color": "#ffffff"
|
| 12 |
-
}
|
|
|
|
| 2 |
"short_name": "Transcreation Sandbox",
|
| 3 |
"name": "Transcreation Sandbox - Translation Practice Tool",
|
| 4 |
"icons": [
|
| 5 |
+
<<<<<<< HEAD
|
| 6 |
{ "src": "/favicon-192.png", "sizes": "192x192", "type": "image/png" },
|
| 7 |
{ "src": "/favicon-512.png", "sizes": "512x512", "type": "image/png" }
|
| 8 |
+
=======
|
| 9 |
+
{
|
| 10 |
+
"src": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAQKADAAQAAAABAAAAQAAAAABGUUKwAAAMZklEQVR4Ae1ae3CU1RW/j+/b3YTwCAaniFZqKU7LjC2i1hkYjAyGhEikonY6nVZpHUboQIiAj7HVYP+oUpFAWoeq1Pe0FsdXC0l4KHWKjKJjHUWr+ECwpUVBBCHZ7/vuPf2duw+WEEx2s/BHuzfZfPe7z3N+59xzzj0bIUqlhEAJgRICJQRKCJQQKCFQQqCEQAmB/0cE5MlketY48suGJc/S2jvbCnmmkmIoCPCsFYeEpE+MoR2+8t4buHbxrmbRbE8GbScFgMba4Hzf11cRyRoSYrRWMiF72NmAZSI6CMbfBiAd1pgnW9bG/n4igeiBjOJt11QXXqQ8vUgIWeNp4UPSwgIBwqd7IUFC8g8ogma4T2REEqPXEZlld6/xn+8+pxjvJwSABdVUJSrsL6VU1yolPGPAhvtlkgl7Zn+zPKRAYWQkD+UB7gXACWuJf/4QWHVba5t8PzupCJWiAzB3SnBBzPd+73lyTBQx1xmmhNQqJVlWdWhDF3o70ctnPQ6GK3wwy8UwBFk1kYJB4L6uJG0XVk5f2ibfSo10f+W8+uDcuNL1kQlfXrY20Z7T12vV63VEHgMaa6JLfV89pLQcGkYZxqX0lJCs+mD8tcjYNoDyNyL9gaTOAxQnKwNdBls4PDRqrJRyitDyYl/Lgbw1QDxkQnrJBPS00qr9121yO7cvmEpnYtUGnJmr8Hqh70kvCOWPuC+fUjQNmF8TTffj6jEQVM4SZtkrHGg+0zai58japbt26Q2rt8mgNwKvn0qjBdkf4wjttUb8eVmHfI/n3Dh53+AgNmgKgPg+Vr4YGlXpbAr6TGQ/ikidgyNyoLf1c/uLAsD8unCS5+tnQFQFmMcBJqi7ZIO310bi5kFtYlUzxJW7cV/rs6ZReYURkzB9BrTjEq3lCJ7LIGeOCbRFJIPorpY2HwY3v9LvI/CzqV2jPa0fyTAPsiSIhETEWyYIf9iyPn83NguSrkgMGg+7MB3rXaI9OVLBmjLTEcOYMiyoQH7YGN4iUNZ7ND/WU6P7BcA11ZSIS1oFaZ8WsuUCNR4kbyJ689Ch5LSVm8p29JWo2fVUWUZivFT2MsQLk5WSI9losgdhxk3GKPI2aS/C9pXHhAG9OKTj9jf6ulfuuH4BMKTMLoLRm5BmniAkSIN2GyOv6AvzC6ZRlbFmIoTYICVNguackZE0n22cf8iaXWKmZFxk+l0SWxl4FPtwoZFjwQDMrUt+C6p5Q1ol2djh6JMxxl63vN17J0Ny9+f8KTRca1MNC9kA7i7ytR4O4NJSZok7EfNJ4sgoVdwT764rDQL6JbQNXmK3ifSz3ffp63vBAGjp3eppWRHC16dUX4hkkh4A88cQM7+2c6TnJS6GfYTbogla6SpmjiND5hf2wmk1H+5UQScD6t4d99ycraSqBPcqRVdkn/rtRr03PTHvB7DPvyDwGOd56nswPq6wq0P908Amb+++2vX15g4/Fn9dacHB0XRY8irWGp7Lap7iMV3J8J8Ggt0oB0GII3K4d4OgHZC+EZGw6kHekw0nP/MtBQGgSc2G8YnBLjnT5IxVZB+8Z135rlwCZk/YXwlCZ+IzKM00PFeaAWbS1fmJWazyHP7iyYyj4C4kdkQRPRUEtikMTb0l2gsA3XC3p6UXK9vFq02XHh5R5g28JXfvvtbzBmBuHQ0TUjU4PwyKmVYQ2WXC6IHum8YGVYyHhziVxzouU4yyNDGNmXSM5kxjFwqPb2i9DBHd7Rfn3L1GXd7SpltWtHtrcSd4Bv08zU1EcOXiC7Lxa6VSlwrRnDc/+U+QZmLMl8Pg6vZAmntZElDlra0bY2/ncOKqkGQDGzgcVeceEc+z3eLLDSI82t19vAMEINlILl/aLrcu2Sz5anykGLsKam8QZjDoO63QT7NAtFZzAOnAOdVzyo8M7lutAABkNWsuGPgTxBhnDQACz4F4lm+23DiZcCadplhjaVcUUnsYisVRZKZ2dspvY403GDxmOjPRaZOhj2Jx8UJ2oZzK7sHeSwDv5RibbkuPctirhW30PXEqYxyPD4vlDO9TtQAvIMeCkc0g+h8IQSvgqxG2q1e670blIDEUC2Dl34kFcvudG+TnmTGNU+m78CCTUkfDyZ273G0RF5+/LFmjjpZ8euLq1dI01pqHkqE4T4RqFaR/utY0x123YT2Shz7PYJnZqtdnXgDMGveKD7X/CgKPRUrrC1liYCISSuzsvtOSZ536Pta9nd+VoEWI9DwGL1WwUGotKJZ9PNPa09PK5Jow8Eev2OB/0FRv7oU3qnRASnE4YQ7iip1fyesIDEkMSwCAdw906Tbo4EiGG0a7K1JdWen2tj0CoXMR8U1zAdSRwbD8Lgja9u+PvZeONB9ba20r/3ho0rsRF7DxOPtXhwDRHUMh9izbcvqJBWB/2WfKhuEfH9wkuxCE+qDZOS6KEs7OH0vusS1S2wWw5DirgM8twGNg/blO9Hhfrst7y3AF0HoZGHfrpAAgGOGj7dCxux/bkpcGnDah8qBX+elqtwzR/vRyZZ4v+hSEzK0LxiJZMoODoDSxLpJgX4oEyiFpwy9V//R+yJfYm5EAOT9lQ4Acq6KlzZn+fJ552YDmZnen73QbkH0HKQ8BdfYoNKPQ9mZvG3vK+znGx3Fh4qEsc1fYG4RWtC3rSLjER6a9p6fLPWh5UwpEXgfgGfFFZPTzPY3vrS0vDchdTJL3Anwx3wChwEhj9VKaptBkMH+ZI9xFfZiQxgEXIDKBWdnLEqJxcudXldKroDHxTBDJYTIuFC/8Zp38sLf5PfUXDMA/d731KojYyotqpa5g4nragNs4qyN9WgJDpx3TuMilFAANiOzgxjbvHuJtOt58br9h/CcDdTz+CO4TI1OqD/RwdFyqPbK/+7K5X9ZXMACrt40JKLK3g3hCIFIl/XjrlWOox0BkgLG/wJkd283yOwwI5pOMvZN9/PEI5cRLVHnKA74vJx5Zg5MvLiLc0rmPvVJhpWAAeLuWDm9NGNrFLIVEQjacfiY9Mb+evtlcTVnbMr82uhxSW3jkzPJMZ/IdAwipN/5r8PEZWFhDA4YOoIcB4Ax2ea7wdHzc9wXG3Hbvq7g5FFj6BQDvuaJdL04mzU+CgN5A7H+JInpif8I0cF9jTTgRydL7cXf1YO7Rwm6KnzAb4ADak7RG3nI86V83iUaQT09D8lemmHdzeb7wWfqGHl6+zl/vGgr8w1gWpdTVbY+P6hwxzIuXHUYae19THdVoTzyGY4q0FwhHzivLO3aEREWQtEuXtemFPRHgwIvp+xAyj4aHSBfnNdnzCBvS+yZ5ePzyjRX/yfQW8iwaALmbXz/VzEPu/lcQcjkfj7TU8XQaIMGUCEN6LaLPqlvbTjkqj88Gc4C1CxEq34RPGcf56WluHXf/xjdKQZepa13v/xWN/SrZs9qvVdKTG2twyYnRbcgB1LGrx/d56MlgzMzjHgBXgBTYvshEM1s7cpkniYvONI/oVsT349jYpfKDmO9mchLIJQIICZJ5xWCe6SkYACijnFf3XszTo6qQuuE83w+kEnVgPna0wXPUYyvOYeLqaykZhPaa1nWx15kANnJWmlrpizlS6klYgwMbHo8Pg5d6YirCLiGCILp5RYd/P6pFKRnx5L0Y5+DKdcVi5Xsz454cxMJmxvFIU84PLikmnOoS8oZBMDsuYm1GR+fhq6+pQOUyaMXZPDLr3/klyzwYZ+4JOZDQLmrp0C2uu0h/CgaA959TTRWxMlOLXP5MKOdFMHoDmG0+9459F65lAeCc+VYp1C5I+QKMP4MTnjyOGUe+L3tYuC1FWCopiqOwx3TZ2S0bvCfRVdTSLwByKWmspbOVsrXQ9Bow+B0wMRzGzgk+M46vvPxhbWGm4cYOg+8PcAvEt9vqLIxjLUfBccFAfkG4vb4rCBvv2RDHba/4pWgA5JLWNOXzoVYO+rpS5hvgZST4PRWgVOA/Adg27kcqeyfet0fW+IjmcATUDAQGQ1nuDiRw7nJ+lu4Y0qnua94k3bcPuXsUq35CAOiNuKYpXaOE9n8K9bgaUeJwPjLMOJ8YqPsOGMpVnVbdu3Kd3NPbWv3tPwkAkJxb90WVpsQY6PUEfOrB7IUJH1IG4/zNEhhmRrfISK7ef/BA26otg/f1l7G+zi/YDfZ1AwhVNEX4Tt+D4ZPia8jl70QS8d1Dxu5VJD7E+5uKvG13nQRp95Xm0rgSAiUESgiUECghUEKghEAJgRICJQT+9xH4LzpXYyOcWn3pAAAAAElFTkSuQmCC",
|
| 11 |
+
"sizes": "192x192",
|
| 12 |
+
"type": "image/png"
|
| 13 |
+
}
|
| 14 |
+
>>>>>>> d5a71c8 (Align top-level backend routes to support image-only content (week>=3), remove legacy content-required validations)
|
| 15 |
],
|
| 16 |
"start_url": ".",
|
| 17 |
"display": "standalone",
|
| 18 |
"theme_color": "#000000",
|
| 19 |
"background_color": "#ffffff"
|
| 20 |
+
}
|
server/routes/auth.js
CHANGED
|
@@ -436,7 +436,6 @@ router.get('/admin/weekly-practice', authenticateToken, async (req, res) => {
|
|
| 436 |
});
|
| 437 |
|
| 438 |
|
| 439 |
-
|
| 440 |
// Create weekly practice task (admin only)
|
| 441 |
router.post('/admin/weekly-practice', authenticateToken, requireAdmin, async (req, res) => {
|
| 442 |
try {
|
|
@@ -447,19 +446,19 @@ router.post('/admin/weekly-practice', authenticateToken, requireAdmin, async (re
|
|
| 447 |
if (!weekNumber) {
|
| 448 |
return res.status(400).json({ error: 'Week number is required' });
|
| 449 |
}
|
| 450 |
-
|
| 451 |
// For week 3+, allow either content or imageUrl
|
| 452 |
if (parseInt(weekNumber) >= 3) {
|
| 453 |
-
if (!content && !imageUrl) {
|
| 454 |
return res.status(400).json({ error: 'Either content or imageUrl is required' });
|
| 455 |
}
|
| 456 |
} else {
|
| 457 |
// For weeks 1-2, require content
|
| 458 |
-
if (!content) {
|
| 459 |
return res.status(400).json({ error: 'Content is required' });
|
| 460 |
}
|
| 461 |
}
|
| 462 |
-
|
| 463 |
const newPractice = new SourceText({
|
| 464 |
content: content || (imageUrl ? 'Image-based practice' : ''),
|
| 465 |
weekNumber: parseInt(weekNumber),
|
|
@@ -474,9 +473,9 @@ router.post('/admin/weekly-practice', authenticateToken, requireAdmin, async (re
|
|
| 474 |
...(imageUrl && (!content || content.trim() === '') && { imageAlignment: imageAlignment || 'center' }),
|
| 475 |
translationBrief
|
| 476 |
});
|
| 477 |
-
|
| 478 |
const savedPractice = await newPractice.save();
|
| 479 |
-
|
| 480 |
res.status(201).json({
|
| 481 |
success: true,
|
| 482 |
message: 'Weekly practice created successfully',
|
|
@@ -563,19 +562,19 @@ router.post('/admin/tutorial-tasks', authenticateToken, requireAdmin, async (req
|
|
| 563 |
if (!weekNumber) {
|
| 564 |
return res.status(400).json({ error: 'Week number is required' });
|
| 565 |
}
|
| 566 |
-
|
| 567 |
// For week 3+, allow either content or imageUrl
|
| 568 |
if (parseInt(weekNumber) >= 3) {
|
| 569 |
-
if (!content && !imageUrl) {
|
| 570 |
return res.status(400).json({ error: 'Either content or imageUrl is required' });
|
| 571 |
}
|
| 572 |
} else {
|
| 573 |
// For weeks 1-2, require content
|
| 574 |
-
if (!content) {
|
| 575 |
return res.status(400).json({ error: 'Content is required' });
|
| 576 |
}
|
| 577 |
}
|
| 578 |
-
|
| 579 |
const newTask = new SourceText({
|
| 580 |
content: content || (imageUrl ? 'Image-based task' : ''),
|
| 581 |
weekNumber: parseInt(weekNumber),
|
|
@@ -590,9 +589,9 @@ router.post('/admin/tutorial-tasks', authenticateToken, requireAdmin, async (req
|
|
| 590 |
...(imageUrl && (!content || content.trim() === '') && { imageAlignment: imageAlignment || 'center' }),
|
| 591 |
translationBrief
|
| 592 |
});
|
| 593 |
-
|
| 594 |
const savedTask = await newTask.save();
|
| 595 |
-
|
| 596 |
res.status(201).json({
|
| 597 |
success: true,
|
| 598 |
message: 'Tutorial task created successfully',
|
|
|
|
| 436 |
});
|
| 437 |
|
| 438 |
|
|
|
|
| 439 |
// Create weekly practice task (admin only)
|
| 440 |
router.post('/admin/weekly-practice', authenticateToken, requireAdmin, async (req, res) => {
|
| 441 |
try {
|
|
|
|
| 446 |
if (!weekNumber) {
|
| 447 |
return res.status(400).json({ error: 'Week number is required' });
|
| 448 |
}
|
| 449 |
+
|
| 450 |
// For week 3+, allow either content or imageUrl
|
| 451 |
if (parseInt(weekNumber) >= 3) {
|
| 452 |
+
if ((!content || content.trim() === '') && !imageUrl) {
|
| 453 |
return res.status(400).json({ error: 'Either content or imageUrl is required' });
|
| 454 |
}
|
| 455 |
} else {
|
| 456 |
// For weeks 1-2, require content
|
| 457 |
+
if (!content || content.trim() === '') {
|
| 458 |
return res.status(400).json({ error: 'Content is required' });
|
| 459 |
}
|
| 460 |
}
|
| 461 |
+
|
| 462 |
const newPractice = new SourceText({
|
| 463 |
content: content || (imageUrl ? 'Image-based practice' : ''),
|
| 464 |
weekNumber: parseInt(weekNumber),
|
|
|
|
| 473 |
...(imageUrl && (!content || content.trim() === '') && { imageAlignment: imageAlignment || 'center' }),
|
| 474 |
translationBrief
|
| 475 |
});
|
| 476 |
+
|
| 477 |
const savedPractice = await newPractice.save();
|
| 478 |
+
|
| 479 |
res.status(201).json({
|
| 480 |
success: true,
|
| 481 |
message: 'Weekly practice created successfully',
|
|
|
|
| 562 |
if (!weekNumber) {
|
| 563 |
return res.status(400).json({ error: 'Week number is required' });
|
| 564 |
}
|
| 565 |
+
|
| 566 |
// For week 3+, allow either content or imageUrl
|
| 567 |
if (parseInt(weekNumber) >= 3) {
|
| 568 |
+
if ((!content || content.trim() === '') && !imageUrl) {
|
| 569 |
return res.status(400).json({ error: 'Either content or imageUrl is required' });
|
| 570 |
}
|
| 571 |
} else {
|
| 572 |
// For weeks 1-2, require content
|
| 573 |
+
if (!content || content.trim() === '') {
|
| 574 |
return res.status(400).json({ error: 'Content is required' });
|
| 575 |
}
|
| 576 |
}
|
| 577 |
+
|
| 578 |
const newTask = new SourceText({
|
| 579 |
content: content || (imageUrl ? 'Image-based task' : ''),
|
| 580 |
weekNumber: parseInt(weekNumber),
|
|
|
|
| 589 |
...(imageUrl && (!content || content.trim() === '') && { imageAlignment: imageAlignment || 'center' }),
|
| 590 |
translationBrief
|
| 591 |
});
|
| 592 |
+
|
| 593 |
const savedTask = await newTask.save();
|
| 594 |
+
|
| 595 |
res.status(201).json({
|
| 596 |
success: true,
|
| 597 |
message: 'Tutorial task created successfully',
|