guoziyun преди 11 месеца
родител
ревизия
9335a4b175
променени са 100 файла, в които са добавени 980 реда и са изтрити 16 реда
  1. 58 3
      app.js
  2. 11 0
      dist/.well-known/apple-app-site-association
  3. 8 0
      dist/.well-known/assetlinks.json
  4. BIN
      dist/anc/images/screentshot_01.webp
  5. BIN
      dist/art-coloring-book.pdf
  6. BIN
      dist/assets/app/screenshot-1.webp
  7. BIN
      dist/assets/app/screenshot-2.webp
  8. BIN
      dist/assets/app/screenshot-3.webp
  9. BIN
      dist/assets/app/screenshot-4.webp
  10. BIN
      dist/assets/app/screenshot-5.webp
  11. BIN
      dist/assets/app/screenshot-6.webp
  12. BIN
      dist/assets/coloring-pages/butterfly-16-9.webp
  13. BIN
      dist/assets/coloring-pages/butterfly-3-1.webp
  14. BIN
      dist/assets/coloring-pages/cat-16-9.webp
  15. BIN
      dist/assets/coloring-pages/cat-3-1.webp
  16. BIN
      dist/assets/coloring-pages/christmas-16-9.webp
  17. BIN
      dist/assets/coloring-pages/christmas-3-1.webp
  18. BIN
      dist/assets/coloring-pages/dragon-16-9.webp
  19. BIN
      dist/assets/coloring-pages/dragon-3-1.webp
  20. BIN
      dist/assets/coloring-pages/fantasy-16-9.webp
  21. BIN
      dist/assets/coloring-pages/fantasy-3-1.webp
  22. BIN
      dist/assets/coloring-pages/flower-16-9.webp
  23. BIN
      dist/assets/coloring-pages/flower-3-1.webp
  24. BIN
      dist/assets/coloring-pages/food-16-9.webp
  25. BIN
      dist/assets/coloring-pages/food-3-1.webp
  26. BIN
      dist/assets/coloring-pages/girl-16-9.webp
  27. BIN
      dist/assets/coloring-pages/girl-3-1.webp
  28. BIN
      dist/assets/coloring-pages/mandala-16-9.webp
  29. BIN
      dist/assets/coloring-pages/mandala-3-1.webp
  30. BIN
      dist/assets/coloring-pages/patterns-16-9.webp
  31. BIN
      dist/assets/coloring-pages/patterns-3-1.webp
  32. BIN
      dist/assets/coloring-pages/peacock-16-9.webp
  33. BIN
      dist/assets/coloring-pages/peacock-3-1.webp
  34. BIN
      dist/assets/coloring-pages/place-16-9.webp
  35. BIN
      dist/assets/coloring-pages/place-3-1.webp
  36. BIN
      dist/assets/coloring-pages/simple-16-9.webp
  37. BIN
      dist/assets/coloring-pages/simple-3-1.webp
  38. BIN
      dist/assets/coloring-pages/unicorn-16-9.webp
  39. BIN
      dist/assets/coloring-pages/unicorn-3-1.webp
  40. BIN
      dist/assets/coloring-pages/video-coloring-pages.webp
  41. BIN
      dist/assets/coloring-pages/zen-16-9.webp
  42. BIN
      dist/assets/coloring-pages/zen-3-1.webp
  43. BIN
      dist/assets/coloring-pages/zentangle-16-9.webp
  44. BIN
      dist/assets/coloring-pages/zentangle-3-1.webp
  45. BIN
      dist/assets/icon/404-opt-1200.webp
  46. BIN
      dist/assets/icon/app.webp
  47. BIN
      dist/assets/icon/logo2.png
  48. BIN
      dist/assets/icon/logo3.png
  49. BIN
      dist/assets/icon/logo3.webp
  50. BIN
      dist/assets/icon/logo4.png
  51. BIN
      dist/assets/icon/logo5.webp
  52. BIN
      dist/assets/icon/logo6.png
  53. BIN
      dist/assets/icon/newlogo.png
  54. BIN
      dist/assets/icon/newlogo.webp
  55. BIN
      dist/assets/icon/noresult.webp
  56. BIN
      dist/assets/icon/screenshot_01.webp
  57. BIN
      dist/assets/images/app-tutorial-poster.webp
  58. BIN
      dist/assets/images/brand.webp
  59. BIN
      dist/assets/images/hero.webp
  60. 2 0
      dist/assets/svg/facebook.svg
  61. 6 0
      dist/assets/svg/instagram.svg
  62. 19 0
      dist/assets/svg/pinterest.svg
  63. 19 0
      dist/assets/svg/twitter.svg
  64. BIN
      dist/assets/tips-tricks/benefit-of-coloring-pages-1200x400.webp
  65. BIN
      dist/assets/tips-tricks/benefit-of-coloring-pages-600x400.webp
  66. BIN
      dist/assets/tips-tricks/choose-the-right-coloring-tools.webp
  67. BIN
      dist/assets/tips-tricks/color-combinations-guide.webp
  68. BIN
      dist/assets/tips-tricks/coloring-techniques-for-beginnersl.webp
  69. BIN
      dist/assets/tips-tricks/coloring-tools-for-mandala.webp
  70. BIN
      dist/assets/tips-tricks/display-your-coloring-masterpieces.webp
  71. BIN
      dist/assets/tips-tricks/flat-coloring.webp
  72. BIN
      dist/assets/tips-tricks/how-to-color-mandala.webp
  73. BIN
      dist/assets/tips-tricks/how-to-color-online.webp
  74. BIN
      dist/assets/tips-tricks/mandala-play.webp
  75. BIN
      dist/assets/tips-tricks/multi-layer.webp
  76. BIN
      dist/assets/tips-tricks/myworks.webp
  77. BIN
      dist/assets/tips-tricks/play.webp
  78. BIN
      dist/assets/tips-tricks/play2.webp
  79. BIN
      dist/assets/tips-tricks/single-layer.webp
  80. BIN
      dist/assets/tips-tricks/smooth-application.webp
  81. BIN
      dist/assets/tips-tricks/uneven-coloring.webp
  82. BIN
      dist/assets/tips-tricks/with-outline.webp
  83. BIN
      dist/assets/tips-tricks/with-shading.webp
  84. BIN
      dist/assets/tips-tricks/without-outline.webp
  85. BIN
      dist/assets/video/art-number-coloring.mp4
  86. BIN
      dist/assets/video/paint-by-number.mp4
  87. 20 0
      dist/manifest.json
  88. 1 1
      dist/myworks.css
  89. 33 0
      dist/scripts/progress2.js
  90. 13 0
      dist/scripts/script.js
  91. 1 0
      dist/stylesheets/header.css
  92. 9 9
      dist/stylesheets/styles.css
  93. 624 0
      dist/stylesheets/v2/styles.css
  94. 2 2
      libs/pager.js
  95. 1 0
      libs/utils/index.js
  96. 61 0
      libs/utils/mail.js
  97. 5 1
      models/index.js
  98. 44 0
      models/schema-comment.js
  99. 26 0
      models/schema-contact.js
  100. 17 0
      models/schema-subscribe.js

+ 58 - 3
app.js

@@ -8,6 +8,24 @@ const cookieParser = require('cookie-parser');
 const bodyParser = require('body-parser');
 const bodyParser = require('body-parser');
 const compression = require('compression');
 const compression = require('compression');
 const authChecker = require('./libs/auth/checker');
 const authChecker = require('./libs/auth/checker');
+// const helmet = require('helmet'); // 安全中间件,主要添加一些安全头
+const rateLimit = require('express-rate-limit'); // 速率限制,预防ddos攻击
+// const cors = require('cors');
+
+// 使用 Helmet 中间件
+// app.use(helmet());
+
+// 创建速率限制器
+const apiLimiter = rateLimit({
+  windowMs: 15 * 60 * 1000, // 15分钟
+  max: 100, // 每个IP在15分钟内最多100个请求
+  standardHeaders: 'draft-7', // 使用draft-7版本的RateLimit头
+  legacyHeaders: false // 禁用X-RateLimit-*头
+});
+
+app.use('/api/', apiLimiter);  // api 接口启用限制
+
+// app.use(cors()); // 启用CORS
 
 
 app.set('trust proxy', 1) //trust first proxy, get ip
 app.set('trust proxy', 1) //trust first proxy, get ip
 
 
@@ -15,7 +33,10 @@ app.set('trust proxy', 1) //trust first proxy, get ip
 app.set('view engine', 'ejs');
 app.set('view engine', 'ejs');
 
 
 // 设置视图目录
 // 设置视图目录
-app.set('views', path.join(__dirname, 'views'));
+app.set('views', [
+  path.join(__dirname, 'views'),
+  path.join(__dirname, 'views/v2'),
+]);
 
 
 /**
 /**
  * Check should compress.
  * Check should compress.
@@ -79,12 +100,46 @@ app.use('/thumbs/v1', require('./routes/res/thumbs'));
 app.use('/proxy', require('./routes/proxy'));
 app.use('/proxy', require('./routes/proxy'));
 
 
 
 
-app.use('/', require('./routes/index'));
+//v2
+app.use('/', require('./routes/v2/index'));  // 首页和具体分类合集页
+app.use('/coloring-page', require('./routes/v2/detail'))  // 详情页
+app.use('/coloring-pages', require('./routes/v2/coloring-pages')) // 所有精选合集页
+app.use('/coloring-page-gallery', require('./routes/v2/gallery')) // 图库页
+
+
 
 
-app.use('/tools-tricks', require('./routes/tooltricks'));
+//////////////////////////  合集 //////////////////////////////
+app.use('/flower-coloring-pages', require('./routes/v2/coloring-page-collection')) // flower coloring pages 合集
+app.use('/mandala-coloring-pages', require('./routes/v2/coloring-page-collection')) // mandala coloring pages 合集
+app.use('/zentangle-coloring-pages', require('./routes/v2/coloring-page-collection')) // zentangle coloring pages 合集
+app.use('/zen-coloring-pages', require('./routes/v2/coloring-page-collection')) // zen coloring pages 合集
+app.use('/cat-coloring-pages', require('./routes/v2/coloring-page-collection')) // cat coloring pages 合集
+app.use('/butterfly-coloring-pages', require('./routes/v2/coloring-page-collection'))
+app.use('/architecture-coloring-pages', require('./routes/v2/coloring-page-collection'))
+app.use('/simple-coloring-pages', require('./routes/v2/coloring-page-collection'))
+app.use('/girl-coloring-pages', require('./routes/v2/coloring-page-collection'))
+app.use('/fantasy-coloring-pages', require('./routes/v2/coloring-page-collection'))
+app.use('/christmas-coloring-pages', require('./routes/v2/coloring-page-collection'))
+app.use('/patterns-coloring-pages', require('./routes/v2/coloring-page-collection'))
+app.use('/peacock-coloring-pages', require('./routes/v2/coloring-page-collection'))
+app.use('/dragon-coloring-pages', require('./routes/v2/coloring-page-collection'))
+app.use('/unicorn-coloring-pages', require('./routes/v2/coloring-page-collection'))
+app.use('/food-coloring-pages', require('./routes/v2/coloring-page-collection'))
+
+app.use('/video-coloring-pages', require('./routes/v2/video-coloring-page'))
+
+
+app.use('/tips-tricks', require('./routes/v2/tips-tricks'));
 
 
 app.use('/download', require('./routes/res/download'));
 app.use('/download', require('./routes/res/download'));
 
 
+app.use('/api/comment', require('./routes/v2/comment'));  // 评论
+app.use('/api/contact', require('./routes/v2/contact'));  // 联系信息
+app.use('/api/subscribe', require('./routes/v2/subscribe'));  // 用户提交邮箱订阅
+
+
+//v1
+app.use('/', require('./routes/index'));
 
 
 
 
 // catch 404 and forward to error handler
 // catch 404 and forward to error handler

+ 11 - 0
dist/.well-known/apple-app-site-association

@@ -0,0 +1,11 @@
+{
+  "applinks": {
+    "apps": [],
+    "details": [
+      {
+        "appID": "9LV382NQ9X.com.pcoloring.anc",
+        "paths": [ "/coloring-page/*", "/play/*" ]
+      }
+    ]
+  }
+}

+ 8 - 0
dist/.well-known/assetlinks.json

@@ -0,0 +1,8 @@
+[{
+  "relation": ["delegate_permission/common.handle_all_urls"],
+  "target": {
+    "namespace": "android_app",
+    "package_name": "com.pcoloring.art.puzzle.color.by.number",
+    "sha256_cert_fingerprints": ["40:68:76:E9:56:DA:28:BE:AE:61:A9:0C:3C:4D:C2:CF:D6:60:1F:BA:7C:87:24:D0:8B:1E:D6:12:74:90:43:5A"]
+  }
+}]

BIN
dist/anc/images/screentshot_01.webp


BIN
dist/art-coloring-book.pdf


BIN
dist/assets/app/screenshot-1.webp


BIN
dist/assets/app/screenshot-2.webp


BIN
dist/assets/app/screenshot-3.webp


BIN
dist/assets/app/screenshot-4.webp


BIN
dist/assets/app/screenshot-5.webp


BIN
dist/assets/app/screenshot-6.webp


BIN
dist/assets/coloring-pages/butterfly-16-9.webp


BIN
dist/assets/coloring-pages/butterfly-3-1.webp


BIN
dist/assets/coloring-pages/cat-16-9.webp


BIN
dist/assets/coloring-pages/cat-3-1.webp


BIN
dist/assets/coloring-pages/christmas-16-9.webp


BIN
dist/assets/coloring-pages/christmas-3-1.webp


BIN
dist/assets/coloring-pages/dragon-16-9.webp


BIN
dist/assets/coloring-pages/dragon-3-1.webp


BIN
dist/assets/coloring-pages/fantasy-16-9.webp


BIN
dist/assets/coloring-pages/fantasy-3-1.webp


BIN
dist/assets/coloring-pages/flower-16-9.webp


BIN
dist/assets/coloring-pages/flower-3-1.webp


BIN
dist/assets/coloring-pages/food-16-9.webp


BIN
dist/assets/coloring-pages/food-3-1.webp


BIN
dist/assets/coloring-pages/girl-16-9.webp


BIN
dist/assets/coloring-pages/girl-3-1.webp


BIN
dist/assets/coloring-pages/mandala-16-9.webp


BIN
dist/assets/coloring-pages/mandala-3-1.webp


BIN
dist/assets/coloring-pages/patterns-16-9.webp


BIN
dist/assets/coloring-pages/patterns-3-1.webp


BIN
dist/assets/coloring-pages/peacock-16-9.webp


BIN
dist/assets/coloring-pages/peacock-3-1.webp


BIN
dist/assets/coloring-pages/place-16-9.webp


BIN
dist/assets/coloring-pages/place-3-1.webp


BIN
dist/assets/coloring-pages/simple-16-9.webp


BIN
dist/assets/coloring-pages/simple-3-1.webp


BIN
dist/assets/coloring-pages/unicorn-16-9.webp


BIN
dist/assets/coloring-pages/unicorn-3-1.webp


BIN
dist/assets/coloring-pages/video-coloring-pages.webp


BIN
dist/assets/coloring-pages/zen-16-9.webp


BIN
dist/assets/coloring-pages/zen-3-1.webp


BIN
dist/assets/coloring-pages/zentangle-16-9.webp


BIN
dist/assets/coloring-pages/zentangle-3-1.webp


BIN
dist/assets/icon/404-opt-1200.webp


BIN
dist/assets/icon/app.webp


BIN
dist/assets/icon/logo2.png


BIN
dist/assets/icon/logo3.png


BIN
dist/assets/icon/logo3.webp


BIN
dist/assets/icon/logo4.png


BIN
dist/assets/icon/logo5.webp


BIN
dist/assets/icon/logo6.png


BIN
dist/assets/icon/newlogo.png


BIN
dist/assets/icon/newlogo.webp


BIN
dist/assets/icon/noresult.webp


BIN
dist/assets/icon/screenshot_01.webp


BIN
dist/assets/images/app-tutorial-poster.webp


BIN
dist/assets/images/brand.webp


BIN
dist/assets/images/hero.webp


+ 2 - 0
dist/assets/svg/facebook.svg

@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg fill="#000000" width="800px" height="800px" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><path d="M21.95 5.005l-3.306-.004c-3.206 0-5.277 2.124-5.277 5.415v2.495H10.05v4.515h3.317l-.004 9.575h4.641l.004-9.575h3.806l-.003-4.514h-3.803v-2.117c0-1.018.241-1.533 1.566-1.533l2.366-.001.01-4.256z"/></svg>

+ 6 - 0
dist/assets/svg/instagram.svg

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M12 18C15.3137 18 18 15.3137 18 12C18 8.68629 15.3137 6 12 6C8.68629 6 6 8.68629 6 12C6 15.3137 8.68629 18 12 18ZM12 16C14.2091 16 16 14.2091 16 12C16 9.79086 14.2091 8 12 8C9.79086 8 8 9.79086 8 12C8 14.2091 9.79086 16 12 16Z" fill="#0F0F0F"/>
+<path d="M18 5C17.4477 5 17 5.44772 17 6C17 6.55228 17.4477 7 18 7C18.5523 7 19 6.55228 19 6C19 5.44772 18.5523 5 18 5Z" fill="#0F0F0F"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M1.65396 4.27606C1 5.55953 1 7.23969 1 10.6V13.4C1 16.7603 1 18.4405 1.65396 19.7239C2.2292 20.8529 3.14708 21.7708 4.27606 22.346C5.55953 23 7.23969 23 10.6 23H13.4C16.7603 23 18.4405 23 19.7239 22.346C20.8529 21.7708 21.7708 20.8529 22.346 19.7239C23 18.4405 23 16.7603 23 13.4V10.6C23 7.23969 23 5.55953 22.346 4.27606C21.7708 3.14708 20.8529 2.2292 19.7239 1.65396C18.4405 1 16.7603 1 13.4 1H10.6C7.23969 1 5.55953 1 4.27606 1.65396C3.14708 2.2292 2.2292 3.14708 1.65396 4.27606ZM13.4 3H10.6C8.88684 3 7.72225 3.00156 6.82208 3.0751C5.94524 3.14674 5.49684 3.27659 5.18404 3.43597C4.43139 3.81947 3.81947 4.43139 3.43597 5.18404C3.27659 5.49684 3.14674 5.94524 3.0751 6.82208C3.00156 7.72225 3 8.88684 3 10.6V13.4C3 15.1132 3.00156 16.2777 3.0751 17.1779C3.14674 18.0548 3.27659 18.5032 3.43597 18.816C3.81947 19.5686 4.43139 20.1805 5.18404 20.564C5.49684 20.7234 5.94524 20.8533 6.82208 20.9249C7.72225 20.9984 8.88684 21 10.6 21H13.4C15.1132 21 16.2777 20.9984 17.1779 20.9249C18.0548 20.8533 18.5032 20.7234 18.816 20.564C19.5686 20.1805 20.1805 19.5686 20.564 18.816C20.7234 18.5032 20.8533 18.0548 20.9249 17.1779C20.9984 16.2777 21 15.1132 21 13.4V10.6C21 8.88684 20.9984 7.72225 20.9249 6.82208C20.8533 5.94524 20.7234 5.49684 20.564 5.18404C20.1805 4.43139 19.5686 3.81947 18.816 3.43597C18.5032 3.27659 18.0548 3.14674 17.1779 3.0751C16.2777 3.00156 15.1132 3 13.4 3Z" fill="#0F0F0F"/>
+</svg>

+ 19 - 0
dist/assets/svg/pinterest.svg

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    
+    <title>pinterest [#180]</title>
+    <desc>Created with Sketch.</desc>
+    <defs>
+
+</defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="Dribbble-Light-Preview" transform="translate(-220.000000, -7399.000000)" fill="#000000">
+            <g id="icons" transform="translate(56.000000, 160.000000)">
+                <path d="M173.876,7239 C168.399,7239 164,7243.43481 164,7248.95866 C164,7253.05869 166.407,7256.48916 169.893,7258.07936 C169.893,7256.21186 169.88,7256.45286 171.303,7250.38046 C170.521,7248.80236 171.129,7246.19673 172.88,7246.19673 C175.31,7246.19673 173.659,7249.79964 173.378,7251.2174 C173.129,7252.30544 173.959,7253.14238 174.955,7253.14238 C176.864,7253.14238 178.108,7250.71524 178.108,7247.87063 C178.108,7245.69456 176.615,7244.10437 174.042,7244.10437 C169.467,7244.10437 168.307,7249.19966 169.893,7250.79893 C170.292,7251.40294 169.893,7251.43118 169.893,7252.22174 C169.616,7253.05768 167.403,7251.84259 167.403,7248.70757 C167.403,7245.86195 169.727,7242.51518 174.457,7242.51518 C178.191,7242.51518 180.681,7245.27609 180.681,7248.2054 C180.681,7252.13805 178.523,7254.98366 175.37,7254.98366 C174.291,7254.98366 173.295,7254.3978 172.963,7253.72824 C172.36,7256.07371 172.238,7257.26258 171.303,7258.58153 C172.216,7258.83261 173.129,7259 174.125,7259 C179.602,7259 184,7254.56519 184,7249.04235 C183.752,7243.43481 179.353,7239 173.876,7239" id="pinterest-[#180]">
+
+</path>
+            </g>
+        </g>
+    </g>
+</svg>

+ 19 - 0
dist/assets/svg/twitter.svg

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 -2 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    
+    <title>twitter [#154]</title>
+    <desc>Created with Sketch.</desc>
+    <defs>
+
+</defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="Dribbble-Light-Preview" transform="translate(-60.000000, -7521.000000)" fill="#000000">
+            <g id="icons" transform="translate(56.000000, 160.000000)">
+                <path d="M10.29,7377 C17.837,7377 21.965,7370.84365 21.965,7365.50546 C21.965,7365.33021 21.965,7365.15595 21.953,7364.98267 C22.756,7364.41163 23.449,7363.70276 24,7362.8915 C23.252,7363.21837 22.457,7363.433 21.644,7363.52751 C22.5,7363.02244 23.141,7362.2289 23.448,7361.2926 C22.642,7361.76321 21.761,7362.095 20.842,7362.27321 C19.288,7360.64674 16.689,7360.56798 15.036,7362.09796 C13.971,7363.08447 13.518,7364.55538 13.849,7365.95835 C10.55,7365.79492 7.476,7364.261 5.392,7361.73762 C4.303,7363.58363 4.86,7365.94457 6.663,7367.12996 C6.01,7367.11125 5.371,7366.93797 4.8,7366.62489 L4.8,7366.67608 C4.801,7368.5989 6.178,7370.2549 8.092,7370.63591 C7.488,7370.79836 6.854,7370.82199 6.24,7370.70483 C6.777,7372.35099 8.318,7373.47829 10.073,7373.51078 C8.62,7374.63513 6.825,7375.24554 4.977,7375.24358 C4.651,7375.24259 4.325,7375.22388 4,7375.18549 C5.877,7376.37088 8.06,7377 10.29,7376.99705" id="twitter-[#154]">
+
+</path>
+            </g>
+        </g>
+    </g>
+</svg>

BIN
dist/assets/tips-tricks/benefit-of-coloring-pages-1200x400.webp


BIN
dist/assets/tips-tricks/benefit-of-coloring-pages-600x400.webp


BIN
dist/assets/tips-tricks/choose-the-right-coloring-tools.webp


BIN
dist/assets/tips-tricks/color-combinations-guide.webp


BIN
dist/assets/tips-tricks/coloring-techniques-for-beginnersl.webp


BIN
dist/assets/tips-tricks/coloring-tools-for-mandala.webp


BIN
dist/assets/tips-tricks/display-your-coloring-masterpieces.webp


BIN
dist/assets/tips-tricks/flat-coloring.webp


BIN
dist/assets/tips-tricks/how-to-color-mandala.webp


BIN
dist/assets/tips-tricks/how-to-color-online.webp


BIN
dist/assets/tips-tricks/mandala-play.webp


BIN
dist/assets/tips-tricks/multi-layer.webp


BIN
dist/assets/tips-tricks/myworks.webp


BIN
dist/assets/tips-tricks/play.webp


BIN
dist/assets/tips-tricks/play2.webp


BIN
dist/assets/tips-tricks/single-layer.webp


BIN
dist/assets/tips-tricks/smooth-application.webp


BIN
dist/assets/tips-tricks/uneven-coloring.webp


BIN
dist/assets/tips-tricks/with-outline.webp


BIN
dist/assets/tips-tricks/with-shading.webp


BIN
dist/assets/tips-tricks/without-outline.webp


BIN
dist/assets/video/art-number-coloring.mp4


BIN
dist/assets/video/paint-by-number.mp4


+ 20 - 0
dist/manifest.json

@@ -0,0 +1,20 @@
+{
+  "name": "Art Number Coloring",
+  "short_name": "ArtColor",
+  "start_url": "/",
+  "display": "standalone",
+  "background_color": "#ffffff",
+  "theme_color": "#4CAF50",
+  "icons": [
+    {
+      "src": "/assets/icon/icon.webp",
+      "sizes": "180x180",
+      "type": "image/webp"
+    },
+    {
+      "src": "/assets/icon/logo_640x640.webp",
+      "sizes": "640x640",
+      "type": "image/webp"
+    }
+  ]
+}

+ 1 - 1
dist/stylesheets/myworks.css → dist/myworks.css

@@ -16,7 +16,7 @@
   border: none;
   border: none;
   background: none;
   background: none;
   cursor: pointer;
   cursor: pointer;
-  font-size: 1.0rem;
+  font-size: 1.2rem;
   color: #666;
   color: #666;
   transition: all 0.3s ease;
   transition: all 0.3s ease;
   position: relative;
   position: relative;

+ 33 - 0
dist/scripts/progress2.js

@@ -0,0 +1,33 @@
+document.addEventListener('DOMContentLoaded', () => {
+  const METADATA_KEY = '__storage_metadata__';
+
+  const containers = document.querySelectorAll('.coloring-image');
+
+  // 获取本地存储数据
+  const metaData = JSON.parse(localStorage.getItem(METADATA_KEY)) || {};
+
+  containers.forEach(container => {
+    const contentId = container.dataset.contentId;
+    if (metaData[contentId]) {
+      const progress = Math.round(metaData[contentId].progress);
+
+      // 如何已完成,展示work图
+      if (progress >= 100) {
+        const img = container.querySelector('img');  // 获取当前div内的img元素
+        img.src = img.src.replace('/page/', '/work/');
+      }
+
+      // 添加角标
+      const badge = document.createElement('div');
+      badge.className = 'progress-badge';
+      badge.innerHTML = `<span>${progress >= 100 ? '✓' : progress + '%'}</span>`;
+      badge.style.backgroundColor = progress >= 100 ? 'var(--secondary-color)' : 'var(--primary-color)';
+      // 添加渐变动画
+      badge.style.transition = 'background-color 0.3s ease';
+
+      container.appendChild(badge);
+
+
+    }
+  });
+});

+ 13 - 0
dist/scripts/script.js

@@ -0,0 +1,13 @@
+document.addEventListener('DOMContentLoaded', function () {
+  const header = document.getElementById('main-header');
+  const logo = document.getElementById('logo-img');
+  const scrollThreshold = 100; // 滚动多少像素后开始缩小
+
+  window.addEventListener('scroll', function () {
+    if (window.scrollY > scrollThreshold) {
+      header.classList.add('small-header');
+    } else {
+      header.classList.remove('small-header');
+    }
+  });
+});

+ 1 - 0
dist/stylesheets/header.css

@@ -5,6 +5,7 @@
   justify-content: space-between;
   justify-content: space-between;
   align-items: center;
   align-items: center;
   box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
   box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+  text-align: center;
 }
 }
 
 
 .logo {
 .logo {

+ 9 - 9
dist/stylesheets/styles.css

@@ -144,14 +144,14 @@ body {
 }
 }
 
 
 .tag-cloud .tag {
 .tag-cloud .tag {
-    display: inline-block;
-    text-decoration: none;
-    padding: 5px 10px;
-    margin: 5px;
-    border-radius: 5px;
-    cursor: pointer;
-    background-color: #fefefe;
-    transition: color 0.3s ease;
+  display: inline-block;
+  text-decoration: none;
+  padding: 5px 10px;
+  margin: 5px;
+  border-radius: 5px;
+  cursor: pointer;
+  background-color: #fefefe;
+  transition: color 0.3s ease;
 }
 }
 
 
 .tag-cloud a.selected {
 .tag-cloud a.selected {
@@ -161,7 +161,7 @@ body {
 }
 }
 
 
 .tag:hover {
 .tag:hover {
-    transform: scale(2.0); /* 悬停时放大 */
+  transform: scale(2.0); /* 悬停时放大 */
 }
 }
 
 
 
 

+ 624 - 0
dist/stylesheets/v2/styles.css

@@ -0,0 +1,624 @@
+:root {
+  --primary-color: #ff6b6b;
+  --secondary-color: #4ecdc4;
+  --accent-color: #ffd166;
+  --background-color: #f9f9f9;
+  --text-color: #333;
+  --light-text: #666;
+  --border-color: #e0e0e0;
+}
+
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+}
+
+body {
+  background-color: var(--background-color);
+  color: var(--text-color);
+  line-height: 1.6;
+}
+
+.container {
+  max-width: 1200px;
+  margin: 0 auto;
+  padding: 0 20px;
+}
+
+
+main {
+  padding: 40px 0;
+}
+
+section {
+  margin-bottom: 50px;
+  background-color: white;
+  border-radius: 10px;
+  padding: 30px;
+  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
+}
+
+h1 {
+  color: var(--primary-color);
+  font-size: 2.2rem;
+  margin-bottom: 20px;
+  text-align: center;
+}
+
+h2 {
+  color: var(--secondary-color);
+  margin: 25px 0 15px;
+  font-size: 1.8rem;
+}
+
+h3 {
+  color: var(--accent-color);
+  margin: 20px 0 12px;
+  font-size: 1.4rem;
+}
+
+p {
+  margin-bottom: 15px;
+  color: var(--text-color);
+}
+
+a {
+  text-decoration: none;
+}
+
+.highlight {
+  background-color: var(--accent-color);
+  padding: 2px 6px;
+  border-radius: 3px;
+  font-weight: 500;
+}
+
+.breadcrumb {
+  margin: 20px 0;
+  font-size: 1.0rem;
+  color: var(--light-text);
+}
+
+.breadcrumb a {
+  color: var(--primary-color);
+  text-decoration: none;
+}
+
+.breadcrumb a:hover {
+  text-decoration: underline;
+}
+
+.btn {
+  display: inline-block;
+  background-color: var(--primary-color);
+  color: white;
+  border: none;
+  padding: 10px 20px;
+  border-radius: 5px;
+  font-size: 1rem;
+  font-weight: 500;
+  cursor: pointer;
+  transition: background-color 0.3s ease;
+  text-decoration: none;
+  text-align: center;
+  margin-right: 10px;
+  margin-bottom: 10px;
+}
+
+.btn:hover {
+  background-color: #ff4d4d;
+}
+
+.btn-secondary {
+  background-color: var(--secondary-color);
+}
+
+.btn-secondary:hover {
+  background-color: #37b0a8;
+}
+
+.btn-accent {
+  background-color: var(--accent-color);
+  color: var(--text-color);
+}
+
+.btn-accent:hover {
+  background-color: #ffc14d;
+}
+
+.btn-outline {
+  background-color: transparent;
+  border: 2px solid var(--primary-color);
+  color: var(--primary-color);
+}
+
+.btn-outline:hover {
+  background-color: var(--primary-color);
+  color: white;
+}
+
+/* 导航栏基础样式 */
+header {
+  background-color: var(--background-color);
+  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+  position: sticky;
+  height: 160px;
+  top: 0;
+  transition: all 0.3s ease;
+  z-index: 1000;
+}
+
+/* Logo样式 */
+.logo {
+  width: 130px;
+  height: 130px;
+  border-radius: 50%;
+  transition: all 0.3s ease;
+}
+
+/* 缩小后的header样式 */
+.small-header {
+  height: 80px !important;
+}
+
+.small-header #logo-img {
+  width:70px !important;
+  height:70px !important;
+}
+
+.header-container {
+  max-width: 1200px;
+  margin: 0 auto;
+  padding: 0 20px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  height: 100%;
+  min-height: 80px;
+}
+
+
+.nav-logo {
+  display: flex;
+  align-items: center;
+}
+
+.nav-logo img {
+  /* width: 40px;
+  height: 40px; */
+  margin-right: 10px;
+}
+
+.nav-logo span {
+  font-size: 1.2rem;
+  font-weight: 700;
+  color: var(--primary-color);
+}
+
+/* 桌面端导航菜单样式 */
+.nav-menu {
+  display: flex;
+  align-items: center;
+  list-style: none;
+}
+
+.nav-menu li {
+  margin-left: 30px;
+}
+
+.nav-menu a {
+  text-decoration: none;
+  color: var(--text-color);
+  font-size: 1.15rem;
+  font-weight: bold;
+  transition: color 0.3s ease;
+  position: relative;
+}
+
+.nav-menu a.active {
+  color: var(--secondary-color);
+}
+
+.nav-menu a:hover {
+  color: var(--primary-color);
+}
+
+.nav-menu a::after {
+  content: '';
+  position: absolute;
+  width: 0;
+  height: 2px;
+  bottom: -5px;
+  left: 0;
+  background-color: var(--primary-color);
+  transition: width 0.3s ease;
+}
+
+.nav-menu a:hover::after {
+  width: 100%;
+}
+
+/* 下拉内容初始隐藏 */
+.dropdown-menu-btn {
+  display: none;
+  position: absolute;
+  background-color: var(--background-color);
+  min-width: 200px;
+  margin-top: 25px;
+  box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
+  z-index: 1000;
+}
+
+/* 下拉菜单项样式 */
+.dropdown-menu-btn a {
+  color: var(--text-color);
+  padding: 12px 16px;
+  text-decoration: none;
+  display: block;
+}
+
+.dropdown-menu-btn a.selected {
+  color: var(--primary-color);
+}
+
+/* 鼠标悬停时显示下拉菜单 */
+.dropdown-menu:hover .dropdown-menu-btn {
+  display: block;
+}
+
+
+/* 搜索图标样式 */
+.search-icon {
+  margin-left: 20px;
+  color: var(--text-color);
+  font-size: 1.2rem;
+  cursor: pointer;
+  transition: color 0.3s ease;
+}
+
+.search-icon:hover {
+  color: var(--primary-color);
+}
+
+/* 移动端菜单按钮样式 */
+.menu-btn {
+  display: none;
+  background: none;
+  border: none;
+  font-size: 1.8rem;
+  color: var(--text-color);
+  cursor: pointer;
+}
+
+/* 移动端下拉菜单样式 */
+.mobile-menu {
+  position: absolute;
+  top: 100%;
+  left: 0;
+  width: 100%;
+  background-color: white;
+  box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
+  padding: 15px 20px;
+  display: none;
+  animation: fadeIn 0.3s ease;
+}
+
+@keyframes fadeIn {
+  from {
+    opacity: 0;
+    transform: translateY(-10px);
+  }
+
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+.mobile-menu ul {
+  list-style: none;
+}
+
+.mobile-menu li {
+  margin: 15px 0;
+}
+
+.mobile-menu a {
+  text-decoration: none;
+  color: var(--text-color);
+  font-weight: 600;
+  display: block;
+  padding: 8px 0;
+  border-bottom: 1px solid #f0f0f0;
+}
+
+.mobile-menu a:hover {
+  color: var(--primary-color);
+}
+
+.mobile-menu a.active {
+  color: var(--secondary-color);
+}
+
+.coloring-grid {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
+  gap: 25px;
+}
+
+.coloring-card {
+  background-color: white;
+  border-radius: 8px;
+  overflow: hidden;
+  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
+  transition: all 0.3s ease;
+}
+
+.coloring-card:hover {
+  transform: translateY(-5px);
+  box-shadow: 0 8px 15px rgba(0, 0, 0, 0.15);
+}
+
+.coloring-image {
+  aspect-ratio: 1/1;
+  background-color: #fff;
+  overflow: hidden;
+  position: relative;
+}
+
+.coloring-image img {
+  width: 100%;
+  height: auto; 
+  object-fit: contain;
+  aspect-ratio: 1;
+  display: block;
+  transition: transform 0.5s ease;
+}
+
+.coloring-card:hover .coloring-image img {
+  transform: scale(1.05);
+}
+
+.coloring-content {
+  padding: 15px;
+}
+
+.coloring-title {
+  font-weight: 600;
+  margin-bottom: 5px;
+  color: var(--text-color);
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.coloring-category {
+  font-size: 0.9rem;
+  color: var(--light-text);
+}
+
+.coloring-content {
+  padding: 15px;
+}
+
+.coloring-title {
+  font-weight: 600;
+  margin-bottom: 5px;
+  color: var(--text-color);
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.coloring-author {
+  font-size: 0.85rem;
+  color: var(--light-text);
+  margin-bottom: 3px;
+}
+
+.coloring-author a {
+  color: var(--primary-color);
+}
+
+.coloring-meta {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  font-size: 0.8rem;
+  color: var(--light-text);
+  margin-bottom: 8px;
+}
+
+.coloring-tags {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 5px;
+}
+
+.tag {
+  background-color: var(--background-color);
+  color: var(--secondary-color);
+  padding: 3px 8px;
+  border-radius: 15px;
+  font-size: 0.75rem;
+  cursor: pointer;
+  transition: all 0.3s ease;
+}
+
+.tag:hover {
+  background-color: var(--secondary-color);
+  color: white;
+}
+
+/* 进度角标样式 */
+.progress-badge {
+  position: absolute;
+  top: 0px;
+  right: 0px;
+  background: #FF5252;
+  color: white;
+  padding: 4px 8px;
+  border-radius: 0px 8px 0px 8px;
+  font-size: 12px;
+  font-family: Arial, sans-serif;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
+  z-index: 1000;
+}
+
+
+@media (max-width: 768px) {
+  h1 {
+    font-size: 1.8rem;
+  }
+
+  h2 {
+    font-size: 1.5rem;
+  }
+
+  h3 {
+    font-size: 1.3rem;
+  }
+
+  section {
+    padding: 20px;
+  }
+
+  .menu-btn {
+    display: block;
+  }
+
+  .nav-menu {
+    display: none;
+  }
+
+  .mobile-menu {
+    display: none;
+    position: static;
+    box-shadow: none;
+    border-top: 1px solid #f0f0f0;
+  }
+
+  .coloring-grid {
+    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
+    gap: 15px;
+  }
+
+}
+
+
+footer {
+    background-color: var(--text-color);
+    color: white;
+    padding: 60px 0;
+    margin-top: 60px;
+}
+
+.footer-grid {
+    display: grid;
+    grid-template-columns: 1fr;
+    gap: 30px;
+}
+
+@media (min-width: 768px) {
+    .footer-grid {
+        grid-template-columns: repeat(4, 1fr);
+    }
+}
+
+.footer-logo {
+    display: flex;
+    align-items: center;
+    margin-bottom: 15px;
+}
+
+.footer-logo img {
+    width: 50px;
+    height: 50px;
+    border-radius: 50%;
+    margin-right: 10px;
+}
+
+.footer-logo span {
+    font-size: 1.2rem;
+    font-weight: bold;
+}
+
+.footer-text {
+    color: #999;
+    font-size: 0.9rem;
+}
+
+.footer-title {
+    font-size: 1.2rem;
+    font-weight: 600;
+    margin: 10px 0 20px 0;
+    color: white;
+}
+
+.footer-links {
+    list-style: none;
+    margin: 0;
+    padding: 0;
+}
+
+.footer-links li {
+    margin-bottom: 10px;
+}
+
+.footer-links a {
+    color: #999;
+}
+
+.footer-links a:hover {
+    color: var(--primary);
+}
+
+.footer-bottom {
+    border-top: 1px solid #444;
+    margin-top: 40px;
+    padding-top: 20px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+}
+
+@media (min-width: 768px) {
+    .footer-bottom {
+        flex-direction: row;
+        justify-content: space-between;
+    }
+}
+
+.copyright {
+    color: #777;
+    font-size: 0.8rem;
+    margin-bottom: 15px;
+}
+
+@media (min-width: 768px) {
+    .copyright {
+        margin-bottom: 0;
+    }
+}
+
+.footer-social {
+    display: flex;
+    gap: 15px;
+}
+
+.footer-social a {
+    color: #999;
+}
+
+.footer-social a:hover {
+    color: var(--primary-color);
+}
+
+.footer-social img {
+    width: 20px;
+}

+ 2 - 2
libs/pager.js

@@ -140,8 +140,8 @@ async function getListBuilder(params, model, populates) {
   //pagination
   //pagination
   page = parseInt(page) || 1;
   page = parseInt(page) || 1;
   if (page <= 0) page = 1;
   if (page <= 0) page = 1;
-  length = parseInt(length) || 30;
-  if (length <= 0) length = 30;
+  length = parseInt(length) || 32;
+  if (length <= 0) length = 32;
   else if (length > 500) length = 500;
   else if (length > 500) length = 500;
 
 
   let start = (page - 1) * length
   let start = (page - 1) * length

+ 1 - 0
libs/utils/index.js

@@ -4,4 +4,5 @@ module.exports = {
   session: require('./session'),
   session: require('./session'),
   lang: require('./lang'),
   lang: require('./lang'),
   thumb: require('./thumb'),
   thumb: require('./thumb'),
+  mail: require('./mail'),
 };
 };

+ 61 - 0
libs/utils/mail.js

@@ -0,0 +1,61 @@
+"use strict";
+const nodemailer = require("nodemailer");
+const { replay } = require("../../config/translate");
+
+
+
+let DEFAULT_DATA = {
+  // from: 'Art Number Coloring Team<guoziyun@jccy-tech.com>', //必须与认证用户一致
+  from: 'Art Number Coloring Team<art-number-coloring@jccy-tech.com>', //必须与认证用户一致
+  // replayTo: 'art_number_coloring@jccy-tech.com', // 指定回复地址为群组邮箱
+  to: "guoziyun@jccy-tech.com", // list of receivers
+  subject: '无标题',
+  text: "无内容", // plain text body
+  //html: "<b>Hello world?</b>", // html body
+}
+
+async function send(mail) {
+  let transporter = nodemailer.createTransport({
+    host: "smtp.exmail.qq.com",
+    port: 465,
+    secure: true, // true for 465, false for other ports
+    auth: {
+      // user: 'guoziyun@jccy-tech.com', // generated ethereal user
+      // pass: 'NXuoWYuxc773Hz9J', // generated ethereal password
+      user: 'art-number-coloring@jccy-tech.com', // generated ethereal user
+      pass: 'Jccy%5858!', // generated ethereal password
+    },
+  });
+
+
+  let data = JSON.parse(JSON.stringify(DEFAULT_DATA));
+  data = Object.assign(data, mail);
+  try {
+    let info = await transporter.sendMail(data);
+    console.log('Mail', data);
+    console.log("Message sent: %s", info.messageId);
+    // Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321@example.com>
+
+    // Preview only available when sending through an Ethereal account
+    console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
+    return info;
+  } catch (err) {
+    console.error(err);
+  }
+
+}
+
+
+module.exports = {
+  send,
+}
+
+if (require.main == module) {
+  send({
+    subject: 'hello:' + new Date(),
+    text: 'hello',
+    //attachments: [{
+    //  path: './mail.js',
+    //}]
+  }).then(console.log).catch(console.error);
+}

+ 5 - 1
models/index.js

@@ -12,4 +12,8 @@ module.exports.ArtVideoStory = mongoose.model('VideoStory', require('./schema-vi
 module.exports.Translate = mongoose.model('Translate', require('./schema-translate'));
 module.exports.Translate = mongoose.model('Translate', require('./schema-translate'));
 
 
 module.exports.TotalDoneRate = mongoose.model('Total_Done_Rate', require('./schema-total-done-rate'));
 module.exports.TotalDoneRate = mongoose.model('Total_Done_Rate', require('./schema-total-done-rate'));
-module.exports.TagSeo = mongoose.model('TagSeo', require('./schema-tag-seo'));
+module.exports.TagSeo = mongoose.model('TagSeo', require('./schema-tag-seo'));
+
+module.exports.Comment = mongoose.model('Comment', require('./schema-comment'));
+module.exports.Contact = mongoose.model('Contact', require('./schema-contact'));
+module.exports.Subscribe = mongoose.model('Subscribe', require('./schema-subscribe'));

+ 44 - 0
models/schema-comment.js

@@ -0,0 +1,44 @@
+var Schema = require('mongoose').Schema;
+
+const commentSchema = new Schema({
+  page: {
+    type: String, 
+    required: true,
+    trim: true,
+    maxlength: 100,
+  },
+  name: {
+    type: String,
+    required: true,
+    trim: true,
+    maxlength: 100
+  },
+  email: {
+    type: String,
+    required: true,
+    trim: true,
+    lowercase: true,
+    validate: {
+      validator: function (v) {
+        return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v);
+      },
+      message: props => `${props.value} is not a valid email address!`
+    }
+  },
+  comment: {
+    type: String,
+    required: true,
+    trim: true,
+    maxlength: 1000
+  },
+  createdAt: {
+    type: Date,
+    default: Date.now
+  },
+  approved: {
+    type: Boolean,
+    default: false
+  }
+});
+
+module.exports = commentSchema;

+ 26 - 0
models/schema-contact.js

@@ -0,0 +1,26 @@
+var Schema = require('mongoose').Schema;
+
+const contactSchema = new Schema({
+    name: {
+        type: String,
+        required: true
+    },
+    email: {
+        type: String,
+        required: true
+    },
+    subject: {
+        type: String,
+        required: true
+    },
+    message: {
+        type: String,
+        required: true
+    },
+    createdAt: {
+        type: Date,
+        default: Date.now
+    }
+});
+
+module.exports = contactSchema;

+ 17 - 0
models/schema-subscribe.js

@@ -0,0 +1,17 @@
+var Schema = require('mongoose').Schema;
+
+const subscribeSchema = new Schema({
+    email: {
+        type: String,
+        required: true,
+        unique: true,
+        lowercase: true,
+        trim: true
+    },
+    subscribedAt: {
+        type: Date,
+        default: Date.now
+    }
+});
+
+module.exports = subscribeSchema;

Някои файлове не бяха показани, защото твърде много файлове са промени