@underpostnet/underpost 2.97.1 → 2.98.0

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.
Files changed (63) hide show
  1. package/README.md +2 -2
  2. package/cli.md +3 -1
  3. package/conf.js +2 -0
  4. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  5. package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
  6. package/package.json +1 -1
  7. package/scripts/rocky-pwa.sh +200 -0
  8. package/src/api/core/core.service.js +0 -5
  9. package/src/api/default/default.service.js +7 -5
  10. package/src/api/document/document.model.js +1 -1
  11. package/src/api/document/document.router.js +5 -0
  12. package/src/api/document/document.service.js +176 -128
  13. package/src/api/file/file.model.js +112 -4
  14. package/src/api/file/file.ref.json +42 -0
  15. package/src/api/file/file.service.js +380 -32
  16. package/src/api/user/user.model.js +38 -1
  17. package/src/api/user/user.router.js +96 -63
  18. package/src/api/user/user.service.js +81 -48
  19. package/src/cli/db.js +424 -166
  20. package/src/cli/index.js +8 -0
  21. package/src/cli/repository.js +1 -1
  22. package/src/cli/run.js +1 -0
  23. package/src/cli/ssh.js +10 -10
  24. package/src/client/components/core/Account.js +327 -36
  25. package/src/client/components/core/AgGrid.js +3 -0
  26. package/src/client/components/core/Auth.js +11 -3
  27. package/src/client/components/core/Chat.js +2 -2
  28. package/src/client/components/core/Content.js +161 -80
  29. package/src/client/components/core/Css.js +30 -0
  30. package/src/client/components/core/CssCore.js +16 -12
  31. package/src/client/components/core/FileExplorer.js +813 -49
  32. package/src/client/components/core/Input.js +207 -12
  33. package/src/client/components/core/LogIn.js +42 -20
  34. package/src/client/components/core/Modal.js +138 -24
  35. package/src/client/components/core/Panel.js +71 -32
  36. package/src/client/components/core/PanelForm.js +262 -77
  37. package/src/client/components/core/PublicProfile.js +888 -0
  38. package/src/client/components/core/Responsive.js +15 -7
  39. package/src/client/components/core/Router.js +117 -15
  40. package/src/client/components/core/SearchBox.js +322 -116
  41. package/src/client/components/core/SignUp.js +26 -7
  42. package/src/client/components/core/SocketIo.js +6 -3
  43. package/src/client/components/core/Translate.js +148 -0
  44. package/src/client/components/core/Validator.js +15 -0
  45. package/src/client/components/core/windowGetDimensions.js +6 -6
  46. package/src/client/components/default/MenuDefault.js +59 -12
  47. package/src/client/components/default/RoutesDefault.js +1 -0
  48. package/src/client/services/core/core.service.js +163 -1
  49. package/src/client/services/default/default.management.js +454 -76
  50. package/src/client/services/default/default.service.js +13 -6
  51. package/src/client/services/file/file.service.js +43 -16
  52. package/src/client/services/user/user.service.js +13 -9
  53. package/src/client/sw/default.sw.js +107 -184
  54. package/src/db/DataBaseProvider.js +1 -1
  55. package/src/db/mongo/MongooseDB.js +1 -1
  56. package/src/index.js +1 -1
  57. package/src/mailer/MailerProvider.js +4 -4
  58. package/src/runtime/express/Express.js +2 -1
  59. package/src/runtime/lampp/Lampp.js +2 -2
  60. package/src/server/auth.js +3 -6
  61. package/src/server/data-query.js +449 -0
  62. package/src/server/object-layer.js +0 -3
  63. package/src/ws/IoInterface.js +2 -2
package/README.md CHANGED
@@ -18,7 +18,7 @@
18
18
 
19
19
  <!-- badges -->
20
20
 
21
- [![Node.js CI](https://github.com/underpostnet/engine/actions/workflows/docker-image.ci.yml/badge.svg?branch=master)](https://github.com/underpostnet/engine/actions/workflows/docker-image.yml) [![Test](https://github.com/underpostnet/engine/actions/workflows/coverall.ci.yml/badge.svg?branch=master)](https://github.com/underpostnet/engine/actions/workflows/coverall.ci.yml) [![Downloads](https://img.shields.io/npm/dm/underpost.svg)](https://www.npmjs.com/package/underpost) [![Socket Badge](https://socket.dev/api/badge/npm/package/underpost/2.97.1)](https://socket.dev/npm/package/underpost/overview/2.97.1) [![Coverage Status](https://coveralls.io/repos/github/underpostnet/engine/badge.svg?branch=master)](https://coveralls.io/github/underpostnet/engine?branch=master) [![Version](https://img.shields.io/npm/v/underpost.svg)](https://www.npmjs.org/package/underpost) [![License](https://img.shields.io/npm/l/underpost.svg)](https://www.npmjs.com/package/underpost)
21
+ [![Node.js CI](https://github.com/underpostnet/engine/actions/workflows/docker-image.ci.yml/badge.svg?branch=master)](https://github.com/underpostnet/engine/actions/workflows/docker-image.yml) [![Test](https://github.com/underpostnet/engine/actions/workflows/coverall.ci.yml/badge.svg?branch=master)](https://github.com/underpostnet/engine/actions/workflows/coverall.ci.yml) [![Downloads](https://img.shields.io/npm/dm/underpost.svg)](https://www.npmjs.com/package/underpost) [![Socket Badge](https://socket.dev/api/badge/npm/package/underpost/2.98.0)](https://socket.dev/npm/package/underpost/overview/2.98.0) [![Coverage Status](https://coveralls.io/repos/github/underpostnet/engine/badge.svg?branch=master)](https://coveralls.io/github/underpostnet/engine?branch=master) [![Version](https://img.shields.io/npm/v/underpost.svg)](https://www.npmjs.org/package/underpost) [![License](https://img.shields.io/npm/l/underpost.svg)](https://www.npmjs.com/package/underpost)
22
22
 
23
23
  <!-- end-badges -->
24
24
 
@@ -66,7 +66,7 @@ Run dev client server
66
66
  npm run dev
67
67
  ```
68
68
  <!-- -->
69
- ## underpost ci/cd cli v2.97.1
69
+ ## underpost ci/cd cli v2.98.0
70
70
 
71
71
  ### Usage: `underpost [options] [command]`
72
72
  ```
package/cli.md CHANGED
@@ -1,4 +1,4 @@
1
- ## underpost ci/cd cli v2.97.1
1
+ ## underpost ci/cd cli v2.98.0
2
2
 
3
3
  ### Usage: `underpost [options] [command]`
4
4
  ```
@@ -589,6 +589,8 @@ Options:
589
589
  --paths <paths> Comma-separated list of paths to filter database operations.
590
590
  --ns <ns-name> Kubernetes namespace context for database operations (defaults to "default").
591
591
  --macro-rollback-export <n-commits-reset> Exports a macro rollback script that reverts the last n commits (Git integration required).
592
+ --clean-fs-collection Cleans orphaned File documents from collections that are not referenced by any models.
593
+ --clean-fs-dry-run Dry run mode - shows what would be deleted without actually deleting (use with --clean-fs-collection).
592
594
  --dev Sets the development cli context
593
595
  --kubeadm Enables the kubeadm context for database operations.
594
596
  --kind Enables the kind context for database operations.
package/conf.js CHANGED
@@ -39,6 +39,7 @@ const DefaultConf = /**/ {
39
39
  'LogOut',
40
40
  'Router',
41
41
  'Account',
42
+ 'PublicProfile',
42
43
  'Auth',
43
44
  'FullScreen',
44
45
  'RichText',
@@ -91,6 +92,7 @@ const DefaultConf = /**/ {
91
92
  { path: '/account', client: 'Default', ssr: 'Default' },
92
93
  { path: '/docs', client: 'Default', ssr: 'Default' },
93
94
  { path: '/recover', client: 'Default', ssr: 'Default' },
95
+ { path: '/u', client: 'Default', ssr: 'Default' },
94
96
  { path: '/default-management', client: 'Default', ssr: 'Default' },
95
97
  { client: 'Default', ssr: 'Default', path: '/404', title: '404 Not Found' },
96
98
  { client: 'Default', ssr: 'Default', path: '/500', title: '500 Server Error' },
@@ -17,7 +17,7 @@ spec:
17
17
  spec:
18
18
  containers:
19
19
  - name: dd-default-development-blue
20
- image: localhost/rockylinux9-underpost:v2.97.1
20
+ image: localhost/rockylinux9-underpost:v2.98.0
21
21
  # resources:
22
22
  # requests:
23
23
  # memory: "124Ki"
@@ -100,7 +100,7 @@ spec:
100
100
  spec:
101
101
  containers:
102
102
  - name: dd-default-development-green
103
- image: localhost/rockylinux9-underpost:v2.97.1
103
+ image: localhost/rockylinux9-underpost:v2.98.0
104
104
  # resources:
105
105
  # requests:
106
106
  # memory: "124Ki"
@@ -18,7 +18,7 @@ spec:
18
18
  spec:
19
19
  containers:
20
20
  - name: dd-test-development-blue
21
- image: localhost/rockylinux9-underpost:v2.97.1
21
+ image: localhost/rockylinux9-underpost:v2.98.0
22
22
 
23
23
  command:
24
24
  - /bin/sh
@@ -103,7 +103,7 @@ spec:
103
103
  spec:
104
104
  containers:
105
105
  - name: dd-test-development-green
106
- image: localhost/rockylinux9-underpost:v2.97.1
106
+ image: localhost/rockylinux9-underpost:v2.98.0
107
107
 
108
108
  command:
109
109
  - /bin/sh
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "type": "module",
3
3
  "main": "src/index.js",
4
4
  "name": "@underpostnet/underpost",
5
- "version": "2.97.1",
5
+ "version": "2.98.0",
6
6
  "description": "pwa api rest template",
7
7
  "scripts": {
8
8
  "start": "env-cmd -f .env.production node --max-old-space-size=8192 src/server",
@@ -0,0 +1,200 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # rocky-pwa.sh
5
+ # Purpose: Build and install a PWA as a native application on Rocky Linux (RHEL).
6
+ # Usage: sudo ./rocky-pwa.sh <URL> <APP_NAME>
7
+
8
+ if [[ $EUID -ne 0 ]]; then
9
+ echo "ERROR: This script must be run as root." >&2
10
+ exit 1
11
+ fi
12
+
13
+ if [[ $# -lt 2 ]]; then
14
+ echo "Usage: $0 <URL> <APP_NAME>"
15
+ echo "Example: $0 'https://underpost.net' 'Underpost'"
16
+ exit 1
17
+ fi
18
+
19
+ TARGET_URL="$1"
20
+ RAW_NAME="$2"
21
+ # Sanitize name for filesystem (My App -> My_App)
22
+ APP_NAME="${RAW_NAME// /_}"
23
+ DEST_DIR="/opt/$APP_NAME"
24
+
25
+ echo ">>> Starting PWA installation for '$APP_NAME' ($TARGET_URL)"
26
+
27
+ # ------------------------------------------------------------------------------
28
+ # 1. Install Dependencies
29
+ # ------------------------------------------------------------------------------
30
+ echo ">>> Installing system dependencies..."
31
+ # Common Electron/Nativefier requirements
32
+ dnf install -y nodejs desktop-file-utils libXScrnSaver libX11 libXrandr \
33
+ alsa-lib atk at-spi2-core cups-libs wget curl grep \
34
+ || echo "Warning: specific package install failed, proceeding in case they exist..."
35
+
36
+ # ------------------------------------------------------------------------------
37
+ # 2. Install/Update Nativefier
38
+ # ------------------------------------------------------------------------------
39
+ if ! command -v nativefier &> /dev/null; then
40
+ echo ">>> Installing nativefier..."
41
+ npm install -g nativefier || echo "Warning: Global install had issues. Attempting to run via npx..."
42
+ fi
43
+
44
+ # ------------------------------------------------------------------------------
45
+ # 3. Build Application
46
+ # ------------------------------------------------------------------------------
47
+ BUILD_TMP=$(mktemp -d)
48
+ trap 'rm -rf "$BUILD_TMP"' EXIT
49
+
50
+ echo ">>> Building application in temporary directory..."
51
+ cd "$BUILD_TMP"
52
+
53
+ # --single-instance: Only allow one window
54
+ # --internal-urls ".*": Don't open links in external browser (keep user inside app)
55
+ npx --yes nativefier --name "$APP_NAME" \
56
+ --platform linux \
57
+ --arch x64 \
58
+ --single-instance \
59
+ --internal-urls ".*" \
60
+ "$TARGET_URL"
61
+
62
+ # ------------------------------------------------------------------------------
63
+ # 4. Install to /opt
64
+ # ------------------------------------------------------------------------------
65
+ # Nativefier creates a folder named like "Underpost-linux-x64"
66
+ BUILT_FOLDER=$(find . -maxdepth 1 -type d -name "*-linux-x64" | head -n 1)
67
+
68
+ if [[ -z "$BUILT_FOLDER" ]]; then
69
+ echo "ERROR: Build failed. No output directory found."
70
+ exit 1
71
+ fi
72
+
73
+ echo ">>> Installing to $DEST_DIR..."
74
+ rm -rf "$DEST_DIR"
75
+ mv "$BUILT_FOLDER" "$DEST_DIR"
76
+
77
+ # Fix ownership
78
+ chown -R root:root "$DEST_DIR"
79
+ chmod -R 755 "$DEST_DIR"
80
+
81
+ # ------------------------------------------------------------------------------
82
+ # 5. Locate Executable & Fix Nested Structure
83
+ # ------------------------------------------------------------------------------
84
+ # Sometimes Nativefier nests: /opt/App/App-linux-x64/App
85
+ # We want: /opt/App/App
86
+ # Check if the DEST_DIR contains only one folder which is also named *-linux-x64
87
+ NESTED_DIR=$(find "$DEST_DIR" -mindepth 1 -maxdepth 1 -type d -name "*-linux-x64" | head -n 1)
88
+
89
+ if [[ -n "$NESTED_DIR" ]]; then
90
+ echo ">>> Flattening nested directory structure..."
91
+ # Move contents up
92
+ mv "$NESTED_DIR"/* "$DEST_DIR/"
93
+ rmdir "$NESTED_DIR"
94
+ fi
95
+
96
+ # Find the binary
97
+ EXECUTABLE="$DEST_DIR/$APP_NAME"
98
+ if [[ ! -f "$EXECUTABLE" ]]; then
99
+ # Try finding any executable file that isn't a library or helper
100
+ EXECUTABLE=$(find "$DEST_DIR" -maxdepth 2 -type f -executable ! -name "*.so*" ! -name "chrome_sandbox" ! -name "*.sh" | head -n 1)
101
+ fi
102
+
103
+ if [[ -z "$EXECUTABLE" || ! -f "$EXECUTABLE" ]]; then
104
+ echo "ERROR: Could not locate executable file in $DEST_DIR"
105
+ exit 1
106
+ fi
107
+
108
+ echo ">>> Found binary: $EXECUTABLE"
109
+
110
+ # ------------------------------------------------------------------------------
111
+ # 6. System Integration (Symlink, Icon, Desktop File)
112
+ # ------------------------------------------------------------------------------
113
+ BIN_LINK="/usr/local/bin/$APP_NAME"
114
+ echo ">>> Creating symlink at $BIN_LINK..."
115
+ ln -sf "$EXECUTABLE" "$BIN_LINK"
116
+
117
+ # Handle Icon
118
+ ICON_DEST="/usr/share/pixmaps/$APP_NAME.png"
119
+ FOUND_ICON=""
120
+
121
+ # 1. Look in resources
122
+ if [[ -f "$DEST_DIR/resources/app/icon.png" ]]; then
123
+ FOUND_ICON="$DEST_DIR/resources/app/icon.png"
124
+ elif [[ -f "$DEST_DIR/resources/app/icon.ico" ]]; then
125
+ FOUND_ICON="$DEST_DIR/resources/app/icon.ico"
126
+ fi
127
+
128
+ # 2. If not found, try to download from PWA manifest (Simplified)
129
+ if [[ -z "$FOUND_ICON" ]]; then
130
+ echo ">>> Icon not found in build. Attempting to fetch from website..."
131
+ # Simple heuristic: try to grab apple-touch-icon or shortcut icon
132
+ ICON_URL=$(curl -sL "$TARGET_URL" | grep -oP 'rel="(apple-touch-icon|icon|shortcut icon)" href="\K[^"]+' | head -n 1)
133
+
134
+ if [[ -n "$ICON_URL" ]]; then
135
+ # Handle relative URLs
136
+ if [[ "$ICON_URL" != http* ]]; then
137
+ # Remove trailing slash from base if present and leading slash from path
138
+ BASE_URL="${TARGET_URL%/}"
139
+ PATH_URL="${ICON_URL#/}"
140
+ ICON_URL="$BASE_URL/$PATH_URL"
141
+ fi
142
+
143
+ echo ">>> Downloading icon from $ICON_URL..."
144
+ wget -q -O "$BUILD_TMP/downloaded_icon" "$ICON_URL" || true
145
+ if [[ -s "$BUILD_TMP/downloaded_icon" ]]; then
146
+ FOUND_ICON="$BUILD_TMP/downloaded_icon"
147
+ fi
148
+ fi
149
+ fi
150
+
151
+ if [[ -n "$FOUND_ICON" ]]; then
152
+ cp "$FOUND_ICON" "$ICON_DEST"
153
+ chmod 644 "$ICON_DEST"
154
+ echo ">>> Icon installed to $ICON_DEST"
155
+ else
156
+ echo ">>> WARNING: No icon found. Desktop entry will use generic icon."
157
+ fi
158
+
159
+ # Desktop File
160
+ DESKTOP_FILE="/usr/share/applications/$APP_NAME.desktop"
161
+ echo ">>> Creating desktop entry at $DESKTOP_FILE..."
162
+
163
+ cat > "$DESKTOP_FILE" <<EOF
164
+ [Desktop Entry]
165
+ Name=$RAW_NAME
166
+ Exec=$BIN_LINK %U
167
+ Icon=$APP_NAME
168
+ Type=Application
169
+ StartupNotify=true
170
+ Categories=Network;Web;
171
+ Terminal=false
172
+ StartupWMClass=$APP_NAME
173
+ EOF
174
+
175
+ # Update cache
176
+ if command -v update-desktop-database &> /dev/null; then
177
+ update-desktop-database /usr/share/applications || true
178
+ fi
179
+
180
+ # ------------------------------------------------------------------------------
181
+ # 7. Create /bin wrapper with --no-sandbox flag
182
+ # ------------------------------------------------------------------------------
183
+ BIN_WRAPPER="/bin/$APP_NAME"
184
+ echo ">>> Creating wrapper script at $BIN_WRAPPER..."
185
+
186
+ cat > "$BIN_WRAPPER" <<EOF
187
+ #!/usr/bin/env bash
188
+ exec '$DEST_DIR/$APP_NAME' --no-sandbox "\$@"
189
+ EOF
190
+
191
+ chmod 755 "$BIN_WRAPPER"
192
+ echo ">>> Wrapper script created: $BIN_WRAPPER"
193
+
194
+ echo "------------------------------------------------------"
195
+ echo " Installation Complete!"
196
+ echo " App Name: $RAW_NAME"
197
+ echo " Command: $APP_NAME"
198
+ echo " Location: $DEST_DIR"
199
+ echo " Wrapper: $BIN_WRAPPER"
200
+ echo "------------------------------------------------------"
@@ -8,11 +8,6 @@ const CoreService = {
8
8
  post: async (req, res, options) => {
9
9
  /** @type {import('./core.model.js').CoreModel} */
10
10
  const Core = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Core;
11
- if (req.path.startsWith('/sh')) {
12
- if (req.body.stdout) return shellExec(req.body.sh, { stdout: true });
13
- shellExec(req.body.sh, { async: true });
14
- return 'Command "' + req.body.sh + '" running';
15
- }
16
11
  return await new Core(req.body).save();
17
12
  },
18
13
  get: async (req, res, options) => {
@@ -1,5 +1,6 @@
1
1
  import { DataBaseProvider } from '../../db/DataBaseProvider.js';
2
2
  import { loggerFactory } from '../../server/logger.js';
3
+ import { DataQuery } from '../../server/data-query.js';
3
4
 
4
5
  const logger = loggerFactory(import.meta);
5
6
 
@@ -13,12 +14,13 @@ const DefaultService = {
13
14
  /** @type {import('./default.model.js').DefaultModel} */
14
15
  const Default = DataBaseProvider.instance[`${options.host}${options.path}`].mongoose.models.Default;
15
16
  if (req.params.id) return await Default.findById(req.params.id);
16
- const { query, page = 1, limit = 10, sort = { updatedAt: -1 } } = req.query;
17
- const queryPayload = query ? JSON.parse(query) : {};
18
- const skip = (page - 1) * limit;
17
+
18
+ // Parse query parameters using DataQuery helper
19
+ const { query, sort, skip, limit, page } = DataQuery.parse(req.query);
20
+
19
21
  const [data, total] = await Promise.all([
20
- Default.find(queryPayload).sort(sort).limit(limit).skip(skip),
21
- Default.countDocuments(queryPayload),
22
+ Default.find(query).sort(sort).limit(limit).skip(skip),
23
+ Default.countDocuments(query),
22
24
  ]);
23
25
 
24
26
  const totalPages = Math.ceil(total / limit);
@@ -60,7 +60,7 @@ const DocumentDto = {
60
60
  return {
61
61
  path: 'userId',
62
62
  model: 'User',
63
- select: '_id email username profileImageId',
63
+ select: '_id role username profileImageId briefDescription',
64
64
  populate: {
65
65
  path: 'profileImageId',
66
66
  model: 'File',
@@ -16,6 +16,11 @@ const DocumentRouter = (options) => {
16
16
  router.put(`/:id`, authMiddleware, async (req, res) => await DocumentController.put(req, res, options));
17
17
  router.put(`/`, authMiddleware, async (req, res) => await DocumentController.put(req, res, options));
18
18
  router.patch(`/:id/copy-share-link`, async (req, res) => await DocumentController.patch(req, res, options));
19
+ router.patch(
20
+ `/:id/toggle-public`,
21
+ authMiddleware,
22
+ async (req, res) => await DocumentController.patch(req, res, options),
23
+ );
19
24
  router.delete(`/:id`, authMiddleware, async (req, res) => await DocumentController.delete(req, res, options));
20
25
  router.delete(`/`, authMiddleware, async (req, res) => await DocumentController.delete(req, res, options));
21
26
  return router;