domma-cms 0.93.0 → 0.94.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 (64) hide show
  1. package/admin/css/admin.css +1 -1
  2. package/admin/js/app.js +2 -2
  3. package/admin/js/templates/docs/api-actions.html +86 -64
  4. package/admin/js/templates/docs/api-authentication.html +159 -123
  5. package/admin/js/templates/docs/api-builder.html +197 -0
  6. package/admin/js/templates/docs/api-collections.html +199 -259
  7. package/admin/js/templates/docs/api-external.html +225 -0
  8. package/admin/js/templates/docs/api-forms.html +268 -0
  9. package/admin/js/templates/docs/api-layouts.html +70 -45
  10. package/admin/js/templates/docs/api-media.html +57 -80
  11. package/admin/js/templates/docs/api-navigation.html +66 -22
  12. package/admin/js/templates/docs/api-pages.html +109 -129
  13. package/admin/js/templates/docs/api-plugins.html +123 -61
  14. package/admin/js/templates/docs/api-scaffold.html +185 -0
  15. package/admin/js/templates/docs/api-settings.html +72 -64
  16. package/admin/js/templates/docs/api-users.html +74 -107
  17. package/admin/js/templates/docs/api-views.html +68 -54
  18. package/admin/js/templates/docs/components-howto.html +20 -17
  19. package/admin/js/templates/docs/components-reference.html +13 -16
  20. package/admin/js/templates/docs/components-rules.html +7 -6
  21. package/admin/js/templates/docs/components-walkthrough.html +19 -19
  22. package/admin/js/templates/docs/tutorial-crud.html +68 -38
  23. package/admin/js/templates/docs/tutorial-forms.html +51 -35
  24. package/admin/js/templates/docs/tutorial-plugin.html +132 -56
  25. package/admin/js/templates/docs/usage-actions.html +55 -14
  26. package/admin/js/templates/docs/usage-collections.html +108 -0
  27. package/admin/js/templates/docs/usage-cta-shortcode.html +14 -3
  28. package/admin/js/templates/docs/usage-dconfig.html +0 -3
  29. package/admin/js/templates/docs/usage-editions.html +213 -0
  30. package/admin/js/templates/docs/usage-media.html +22 -6
  31. package/admin/js/templates/docs/usage-navigation.html +74 -18
  32. package/admin/js/templates/docs/usage-pages.html +60 -20
  33. package/admin/js/templates/docs/usage-plugins.html +89 -17
  34. package/admin/js/templates/docs/usage-shortcodes.html +123 -70
  35. package/admin/js/templates/docs/usage-site-settings.html +50 -18
  36. package/admin/js/templates/docs/usage-tools.html +73 -0
  37. package/admin/js/templates/docs/usage-users-roles.html +99 -20
  38. package/admin/js/templates/docs/usage-views.html +36 -19
  39. package/admin/js/templates/documentation.html +153 -32
  40. package/admin/js/templates/plugin-guide.html +15 -0
  41. package/admin/js/templates/plugin-guides.html +21 -0
  42. package/admin/js/templates/pro-docs.html +53 -234
  43. package/admin/js/templates/tutorials.html +5 -4
  44. package/admin/js/views/doc-pages.js +1 -1
  45. package/admin/js/views/index.js +1 -1
  46. package/admin/js/views/plugin-guides.js +5 -0
  47. package/bin/cli.js +6 -6
  48. package/package.json +1 -1
  49. package/plugins/blog/docs/guide.md +205 -0
  50. package/plugins/blog/plugin.json +1 -1
  51. package/plugins/feedback/docs/guide.md +95 -0
  52. package/plugins/feedback/plugin.json +1 -1
  53. package/plugins/free-tier.lock.json +16 -11
  54. package/plugins/mail-reader/docs/guide.md +147 -0
  55. package/plugins/mail-reader/plugin.json +1 -1
  56. package/plugins/security/docs/guide.md +170 -0
  57. package/plugins/security/plugin.json +1 -1
  58. package/plugins/shopping-cart/docs/guide.md +191 -0
  59. package/plugins/shopping-cart/plugin.json +1 -1
  60. package/server/routes/api/documentation.js +42 -0
  61. package/server/server.js +12 -0
  62. package/server/services/docs.js +13 -2
  63. package/server/services/pluginGuides.js +255 -0
  64. package/server/services/plugins.js +8 -0
@@ -0,0 +1,170 @@
1
+ ---
2
+ title: Guide
3
+ order: 1
4
+ ---
5
+
6
+ Security protects your site with no set-up. It checks what is weak and tells you how to fix it, locks out repeated wrong passwords, enforces sensible password rules, logs every sign-in and turns away scanners. It is free and comes with Domma CMS, switched on.
7
+
8
+ ## What it does
9
+
10
+ - **Health check**: a list of checks, each with why it matters and how to fix it.
11
+ - **Sign-in lockout**: after repeated wrong passwords, the account or the address is locked for a while, longer each time.
12
+ - **Password rules**: new passwords must be long enough, not a common password, and not contain the person's name or email.
13
+ - **Sign-in log**: every sign-in, failed or successful, and every "Forgot your password?" request.
14
+ - **Scanner guard**: requests for things no Domma site has (WordPress, `.env` files, database dumps and the like) get an empty "not found". An address that keeps probing is blocked for a while.
15
+ - **Blocks**: block an address or range by hand, and see and clear lockouts and blocks.
16
+ - A badge on the Security sidebar entry: the number of health checks needing attention. It turns red only when a failing check is critical.
17
+
18
+ ## Getting started
19
+
20
+ Security is on from the start. To review it:
21
+
22
+ 1. Open [Security](#/plugins/security) in the sidebar.
23
+ 2. Read the **Health** card on the Overview tab. Click a check to see why it matters and how to fix it.
24
+ 3. Fix what you can. Use **Go there** in a check's menu where it offers one.
25
+ 4. Click the cog in the banner to review **Security settings**.
26
+
27
+ ## Screens
28
+
29
+ The screen has three tabs. The banner has **Run the checks again** and **Security settings** (the cog).
30
+
31
+ ### Overview
32
+
33
+ - **Health**: a score and the list of checks, grouped under People, Sign-in, Server, Web and Plugins.
34
+ - Tiles: **Need attention**, **Failed sign-ins, 24h**, **Blocked now**, **Probes refused today** and **Reset requests, 24h**.
35
+
36
+ Right-click a check for **Why, and how to fix it**, **Go there**, **Run the checks again** and **Copy**.
37
+
38
+ The checks include:
39
+
40
+ | Group | Checks |
41
+ |---|---|
42
+ | People | Unused admin accounts, How many admins, Accounts never used |
43
+ | Sign-in | Sign-in lockout, Password rules, Two-factor sign-in, Email for resets and alerts |
44
+ | Server | Domma CMS up to date, Production mode, Visitor addresses, Listening address |
45
+ | Web | HTTPS certificate, Security headers, HTTPS, Private files not served |
46
+ | Plugins | Plugin licences |
47
+
48
+ A check the plugin cannot confirm shows as information, never as a pass. Results are kept for 10 minutes; **Run the checks again** refreshes them.
49
+
50
+ ### Sign-ins
51
+
52
+ - Filters: **All**, **Failed**, **Succeeded** and **Resets**.
53
+ - Period: **Last 24 hours**, **Last 7 days**, **Last 30 days** or **All kept**.
54
+ - A search box for email, address or browser.
55
+ - **CSV** downloads what is shown.
56
+
57
+ Right-click an entry for **Only this address**, **Unlock this account**, **Block this address...**, **Copy the address** and **Copy the browser**.
58
+
59
+ The Resets filter lists "Forgot your password?" requests and what happened to each.
60
+
61
+ ### Blocked
62
+
63
+ - **Locked after wrong passwords**: current lockouts. **Unlock all** clears every one. Right-click one to **Unlock** it.
64
+ - **Blocked for probing**: addresses blocked by the scanner guard. Right-click for **Unblock** or **Block for good**.
65
+ - **Blocked by hand**: your own blocks. Enter an **Address or range** and an optional reason, then click **Block**. Right-click a block for **Remove the block**.
66
+
67
+ An address can be written as:
68
+
69
+ ```text
70
+ 81.2.69.142 one address
71
+ 192.168.1.* a trailing wildcard
72
+ 10.0.0.0/8 an IPv4 range
73
+ 2a00:23c7:* an IPv6 prefix
74
+ ```
75
+
76
+ If a block would cover your own address, you are warned first. The server itself cannot be blocked. Blocked addresses get an empty "forbidden" for every request.
77
+
78
+ ## Settings
79
+
80
+ Click the cog in the banner to open **Security settings**. Click **Save** (or press Ctrl+Enter).
81
+
82
+ ### Sign-in lockout
83
+
84
+ | Setting | Default |
85
+ |---|---|
86
+ | Lock after repeated wrong passwords | On |
87
+ | Wrong passwords on one account | 5 |
88
+ | Wrong passwords from one address | 20 |
89
+ | Counted over (minutes) | 15 |
90
+ | First lock (minutes) | 1. Each lock after that is twice as long |
91
+ | Longest lock (minutes) | 60 |
92
+
93
+ While locked, even the right password does not get in. The message never says whether the account exists. A successful sign-in clears the account's count.
94
+
95
+ ### Password rules
96
+
97
+ | Setting | Default |
98
+ |---|---|
99
+ | Check new passwords | On |
100
+ | Shortest password | 10 (8 to 64) |
101
+ | Refuse the 10,000 most common passwords | On |
102
+ | Refuse passwords containing the person's name or email | On |
103
+
104
+ Passwords are checked when they are set or changed. Existing passwords keep working until then. While the rules are on, a password that uses only one or two different characters (such as `aaaaaaaaaa` or `abababababab`) is always refused.
105
+
106
+ ### Scanners
107
+
108
+ | Setting | Default |
109
+ |---|---|
110
+ | Refuse probes, and block addresses that keep probing | On |
111
+ | Probes before a block | 5 |
112
+ | Counted over (minutes) | 10 |
113
+ | Block for (minutes) | 60 |
114
+ | Also treat as probes | Your own extra paths, one per line, starting with `/` |
115
+ | This site does serve | Paths that look like probes but are real on your site, for example `/legacy/` |
116
+
117
+ An address someone has signed in from in the last 7 days is never blocked automatically. Requests from the server itself are never touched.
118
+
119
+ ### Keeping and telling
120
+
121
+ | Setting | Default |
122
+ |---|---|
123
+ | Keep the sign-in log (days) | 30 (7 to 365) |
124
+ | Admin unused after (days) | 90. The health check flags admins who have not signed in for this long |
125
+ | Notify when an account or address is locked | On |
126
+ | Notify when someone signs in after many wrong passwords | On |
127
+ | Notify when a scanner is blocked | Off |
128
+ | Notify when password resets look like someone trying addresses | On |
129
+
130
+ The last one fires when one address asks about 3 different accounts within an hour, or when 10 requests in an hour name accounts that do not exist.
131
+
132
+ ## Locked out yourself
133
+
134
+ If you cannot sign in because of a lockout or a block, someone with access to the server can clear it. In the site's folder, run:
135
+
136
+ ```text
137
+ node plugins/security/bin/unlock.js --list
138
+ node plugins/security/bin/unlock.js --all
139
+ node plugins/security/bin/unlock.js --ip 81.2.69.142
140
+ node plugins/security/bin/unlock.js --user sam@example.com
141
+ ```
142
+
143
+ `--list` shows what is locked or blocked. `--all` clears everything. `--ip` clears one address and `--user` one account. The site notices within a few seconds, with no restart.
144
+
145
+ ## Permissions and roles
146
+
147
+ In System > Roles, Security adds the permission **Security** with two actions:
148
+
149
+ | Action | Label | Meaning | Granted by default to |
150
+ |---|---|---|---|
151
+ | read | View | See the health check, sign-ins and blocks | Admin |
152
+ | manage | Manage | Change settings; block, unblock and unlock | Admin |
153
+
154
+ Super Admins always have both. Someone with View only sees the screens, but the unlock and block actions are switched off.
155
+
156
+ Security adds no roles.
157
+
158
+ ## Tips
159
+
160
+ - Keep the health check clear. The sidebar badge tells you when something needs attention.
161
+ - Give only a few people admin rights. The health check flags admin accounts that are not used.
162
+ - Set up outgoing email under Settings > Email, so password resets and alerts can be sent.
163
+ - On a site behind a proxy, check **Visitor addresses** in the health check. If the site cannot see real visitor addresses, lockouts and blocks apply to the proxy's address.
164
+ - The CSV export is safe to open in a spreadsheet: cells that could run as formulas are neutralised.
165
+
166
+ ## Limitations
167
+
168
+ - Lockout and password rules need Domma CMS 0.83 or later. On older versions the screen says so and only the scanner guard and health check work.
169
+ - Reset requests are only logged on Domma CMS 0.88 or later.
170
+ - No two-factor sign-in. **Security Pro** adds it, along with more protection. When Security Pro is installed it takes over from Security.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "security",
3
3
  "displayName": "Security",
4
- "version": "1.1.2",
4
+ "version": "1.1.3",
5
5
  "tier": "free",
6
6
  "description": "Keeps a Domma CMS site safe: a health check of what is weak and how to fix it, sign-in lockout after repeated wrong passwords, password rules, a log of every sign-in, and blocking of the scanners that probe every site for WordPress, .env files and the like.",
7
7
  "author": "Domma CMS",
@@ -0,0 +1,191 @@
1
+ ---
2
+ title: Guide
3
+ order: 1
4
+ ---
5
+
6
+ Sell from your own site. Add products, choose how you get paid, and run orders from the Shop in the admin sidebar. Shopping Cart is free.
7
+
8
+ ## What it does
9
+
10
+ - A storefront at `/shop` (you can move it) with category filters, and search and sort once there are more than four products, and a page for each product.
11
+ - Products with pictures, a "was" price, stock counts and options (for example sizes or colours), each option with its own price, SKU and stock.
12
+ - A basket that follows shoppers round the whole site, with a floating basket button.
13
+ - A one-page checkout at `/shop/cart` that takes payment by Stripe, PayPal or offline (for example bank transfer).
14
+ - A receipt page for each order that the shopper can come back to.
15
+ - Orders in the admin: mark paid, fulfil with tracking, refund, cancel, print a packing slip.
16
+ - A badge on the Shop sidebar item showing paid orders waiting to be sent.
17
+
18
+ The free Shopping Cart sends no emails at all - not to the shopper and not to you. The receipt page is the shopper's record of the order. Order confirmation and dispatch emails come with Shopping Cart Pro.
19
+
20
+ ## Getting started
21
+
22
+ 1. Open [Shop](#/plugins/shopping-cart) in the sidebar. A new shop shows "Open your shop" with three steps.
23
+ 2. Click **Add a product**, or **or try samples** to load six sample products with pictures, options and stock. You can edit or delete the samples later.
24
+ 3. Click **Payment settings** and turn on at least one way to pay (see Settings below). Pay offline is on by default.
25
+ 4. Click **See the shop** to check it, then link to `/shop` from your menu or put `[shop-products /]` on any page.
26
+ 5. If your site sits behind a proxy or on an unusual port, set your site's address first: [Site Settings](#/settings) > General > **Site URL** (for example `https://example.com`). Stripe and PayPal send shoppers back to this address after they pay. Without it the Shop guesses the address from the request, which can be wrong behind a proxy.
27
+
28
+ ## Screens
29
+
30
+ The Shop has three tabs under the banner: Overview, Orders and Products. Shopping Cart Pro adds tabs of its own to this row. The banner has three buttons: the cog (Shop settings), open the shop in a new tab, and + (Add a product, on the Products tab).
31
+
32
+ ### Overview
33
+
34
+ - **Today**, **Last 30 days** (compared with the 30 days before), **Average order** and **To fulfil**. Click To fulfil to go to the orders.
35
+ - **Takings, last 30 days** - a bar per day. Hover a bar to see the day, the takings and the number of orders. Only paid and fulfilled orders count; refunded and cancelled orders are left out.
36
+ - **Needs you** - paid orders to send, orders awaiting payment, products low in stock or sold out, checkouts started this week and not paid, and a reminder if you only take offline payment.
37
+ - **Latest orders** and **Best sellers** (by takings over the last 30 days).
38
+
39
+ ### Orders
40
+
41
+ 1. Pick a filter: **To do**, **To fulfil**, **Awaiting payment**, **Fulfilled**, **Started**, **Cancelled & refunded** or **All**. Each shows a count.
42
+ 2. Search by order number, name, email or item.
43
+ 3. Click an order to open it. Right-click a row (or use the ⋮ button, or Shift+F10) for its actions.
44
+
45
+ An open order shows the items and totals, the shopper, the delivery address and tracking, the shopper's note, a **Staff note** only you can see (saved when you click away), the payment reference and the order's history.
46
+
47
+ Order statuses:
48
+
49
+ | Status | Meaning |
50
+ |---|---|
51
+ | Checkout started | The shopper went to pay and has not finished. No stock is held. |
52
+ | Awaiting payment | An offline order. Nothing has been charged. |
53
+ | Paid - to fulfil | Paid. Stock has been taken. Ready to send. |
54
+ | Fulfilled | Sent, delivered or collected. |
55
+ | Cancelled | Never paid, and closed. |
56
+ | Refunded | Paid, then given back. |
57
+
58
+ Actions:
59
+
60
+ - **Mark paid** - for an offline order when the money arrives. Stock is taken at this point.
61
+ - **Mark fulfilled** (or **Mark collected**) - add a carrier, tracking number and tracking link if you have them. The shopper sees the tracking on their receipt page.
62
+ - **Back to "to fulfil"** - reopen a fulfilled order.
63
+ - **Refund** - see below.
64
+ - **Cancel order** - only for orders that were never paid.
65
+ - **Packing slip** - opens a printable slip with the items, SKUs, address and the shopper's note. Allow pop-ups for your site if nothing opens.
66
+ - **Copy receipt link** - the shopper's receipt page address.
67
+ - **Email the shopper** - opens your own email program.
68
+ - **Delete** - only for Checkout started, Awaiting payment and Cancelled orders. A paid or refunded order cannot be deleted.
69
+
70
+ Refunds:
71
+
72
+ - Refunds are full refunds only. You cannot refund part of an order.
73
+ - A Stripe or PayPal order is refunded through Stripe or PayPal first. The order is only marked refunded once they accept it.
74
+ - An offline order is only marked refunded. Give the money back yourself, the way it came.
75
+ - Tick **Put the items back in stock** to return the stock.
76
+
77
+ ### Products
78
+
79
+ 1. Pick a filter: **All**, **On sale**, **Drafts**, **Low stock** or **Archived**.
80
+ 2. Click a product to edit it, or click **Product** (or + in the banner) to add one.
81
+ 3. Right-click a row (or ⋮) to **Edit**, **View in the shop**, **Duplicate**, **Put on sale**, **Back to draft**, **Feature**, set stock, **Archive** or **Delete**.
82
+
83
+ Only products **On sale** appear in the shop. **Archive** hides a product but keeps it. Deleting a product does not change past orders; they keep their own copy.
84
+
85
+ The product form:
86
+
87
+ - **Name**, **Address** (the last part of the product's web address), **Pictures** (from Media; the first is shown on the card, the second on hover; drag to reorder).
88
+ - **Price** and **Was** (an earlier, higher price, shown struck through with a Sale flag).
89
+ - **Summary** (on the card and the top of the product page) and **Description** (Markdown and shortcodes work).
90
+ - **Category**, **Tags** (comma-separated), **Status** (On sale, Draft - hidden, Archived) and **Featured** (shown first, with a Featured flag).
91
+ - **Options & stock** - tick **Count stock** to track stock; it then sells out at 0. Add options with **Add an option**, each with a name, price (empty uses the product's price), SKU and stock. **Options are** names them (for example Size).
92
+ - **Delivery & tax** - untick **Needs delivering** for downloads, services and tickets (no delivery charge, no address asked). **Weight (g)** and **Tax class** are used by Shopping Cart Pro.
93
+
94
+ Ctrl+Enter saves the form.
95
+
96
+ ## Settings
97
+
98
+ Click the cog in the Shop banner to open **Shop settings**. It has four sections. Click **Save** when done. Changing the currency or the shop address reloads the page.
99
+
100
+ ### Storefront
101
+
102
+ - **Shop name**, **Address** (default `/shop`; takes effect at once, and old links stop working), **Introduction**.
103
+ - **Currency** - changing it does not convert prices you have entered.
104
+ - **Products per row** (2, 3 or 4).
105
+ - **Category filters**, **Search box** (shown once there are more than four products), **Basket button on every page**, **Say "Only 3 left"**.
106
+ - **Basket button side** (Right or Left), **Low stock at**.
107
+ - **Terms of sale page** - if set, shoppers must tick "I agree to the terms of sale" before paying.
108
+
109
+ ### Delivery
110
+
111
+ - **We deliver to** - the countries checkout offers. Products that need no delivery can be bought from anywhere.
112
+ - **Delivery charge** - one charge per order, and what it is **Called**.
113
+ - **Free over** - orders at or above this amount go free. 0 means never.
114
+ - **Offer collection** - shoppers can collect in person, with no charge and no address.
115
+
116
+ ### Tax
117
+
118
+ - **Tax rate %** - one rate for every product. Leave at 0 for no tax.
119
+ - **Called** (for example VAT).
120
+ - **My prices include tax** - on: the price is what the shopper pays, and the receipt shows the tax inside it. Off: tax is added at checkout.
121
+ - **Tax the delivery charge too**.
122
+
123
+ ### Payment
124
+
125
+ Turn on one or more:
126
+
127
+ - **Stripe** - cards, Apple Pay and Google Pay on Stripe's own page.
128
+ 1. In Stripe, go to Developers > API keys and copy the secret key (`sk_test_` for testing, `sk_live_` for real).
129
+ 2. Paste it in **Secret key**.
130
+ 3. Optional but recommended: in Stripe, go to Developers > Webhooks, add the **Webhook** address shown in the settings (use the copy button) for the event `checkout.session.completed`, then paste its signing secret in **Webhook signing secret**. This confirms a payment even if the shopper closes the tab before coming back.
131
+ 4. Click **Test the key**.
132
+ - **PayPal** - needs a PayPal Business account and a REST app.
133
+ 1. Choose **Mode**: Sandbox (testing) or Live.
134
+ 2. Paste the **Client ID** and **Secret** from developer.paypal.com > Apps & Credentials > your app.
135
+ 3. Click **Test the keys**.
136
+ - **Pay offline** - bank transfer or cash on collection. The order is placed as Awaiting payment and nothing is charged. Set what it is **Called** and **What to tell the shopper** (for example your bank details). This shows on the shopper's receipt with the order number and total.
137
+
138
+ Keys are kept on the server. Once saved they show as dots and are never shown again. Leave the dots alone to keep the saved key.
139
+
140
+ ## Shortcodes
141
+
142
+ Put products on any page.
143
+
144
+ A grid of products (all options are optional; `limit` is 1 to 48, default 8):
145
+
146
+ ```text
147
+ [shop-products /]
148
+ [shop-products category="Mugs" limit="8" columns="4" /]
149
+ [shop-products tag="gift" /]
150
+ [shop-products featured="true" /]
151
+ ```
152
+
153
+ One product card:
154
+
155
+ ```text
156
+ [shop-product slug="blue-mug" /]
157
+ ```
158
+
159
+ An add-to-basket button with the price. For a product with options it links to the product page instead, so the shopper can choose:
160
+
161
+ ```text
162
+ [buy-button slug="blue-mug" label="Buy now" /]
163
+ ```
164
+
165
+ Only products On sale are shown. A page built from these can show out-of-date stock until it is next rendered, but checkout always checks stock and prices again.
166
+
167
+ ## Permissions and roles
168
+
169
+ Set in System > Roles, under Plugins:
170
+
171
+ | Permission | Action | Lets someone |
172
+ |---|---|---|
173
+ | Shop | See | Open the Shop and read its orders and products |
174
+ | Shop | Manage | Edit products, move and refund orders, change the Shop's settings |
175
+
176
+ The admin role has both by default.
177
+
178
+ ## Tips
179
+
180
+ - Test with Stripe's `sk_test_` key or PayPal Sandbox before going live.
181
+ - Notifications: a notice arrives for each new paid order and for each offline order awaiting payment. A Super Admin can switch the "Shop orders" source off in the Notifications settings.
182
+ - Stock is taken when an order is paid, not when checkout starts. Started checkouts hold no stock and can be deleted.
183
+ - Order numbers start at 1001.
184
+ - If a shopper's basket changes while they check out (something sold out, fewer left), checkout stops and shows the new total before taking payment.
185
+
186
+ ## Limitations
187
+
188
+ - No emails. Shopping Cart Pro adds order and dispatch emails.
189
+ - Refunds are full refunds only.
190
+ - One flat delivery charge and one tax rate. Shopping Cart Pro adds shipping zones, rates by weight or order value, tax by country and tax class, and discount codes.
191
+ - Behind a proxy, set Site URL in Site Settings or Stripe and PayPal may send shoppers back to the wrong address.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "shopping-cart",
3
3
  "displayName": "Shopping Cart",
4
- "version": "1.0.2",
4
+ "version": "1.0.3",
5
5
  "tier": "free",
6
6
  "description": "Sell from your site: products with options, stock and pictures, a storefront and a cart that follows shoppers from page to page, and checkout with Stripe, PayPal or payment offline. Orders to fulfil in the sidebar, refunds from the order.",
7
7
  "author": "Domma CMS",
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Documentation API - plugin guides for the admin's Documentation folder.
3
+ *
4
+ * GET /api/documentation/plugins - the guides this user may read
5
+ * GET /api/documentation/plugins/:name - one guide, its first page rendered
6
+ * GET /api/documentation/plugins/:name/:page - one guide, the named page rendered
7
+ *
8
+ * Signed-in users only. A guide is readable by whoever can use the plugin
9
+ * (services/pluginGuides.js decides), so a role that cannot open Invoices is
10
+ * not shown the Invoices guide either.
11
+ */
12
+ import {authenticate as defaultAuthenticate} from '../../middleware/auth.js';
13
+ import {getPermissionsForRoles} from '../../services/roles.js';
14
+ import {getEffectiveRegistry} from '../../services/permissionRegistry.js';
15
+ import {getEffectiveRoles} from '../../services/userRoles.js';
16
+ import {getGuide, listGuides} from '../../services/pluginGuides.js';
17
+
18
+ /** The caller's permissions - the same union /api/auth/permissions answers. */
19
+ function permissionsOf(user, resolve) {
20
+ if (resolve) return resolve(user);
21
+ const roles = getEffectiveRoles(user || {});
22
+ return getPermissionsForRoles(roles, getEffectiveRegistry().map(r => r.key));
23
+ }
24
+
25
+ export async function documentationRoutes(fastify, opts = {}) {
26
+ const authenticate = opts.authenticate || defaultAuthenticate;
27
+ const signedIn = {preHandler: [authenticate]};
28
+
29
+ fastify.get('/documentation/plugins', signedIn, async (request) => {
30
+ return {guides: listGuides(permissionsOf(request.user, opts.permissionsOf))};
31
+ });
32
+
33
+ const one = async (request, reply) => {
34
+ const {name, page} = request.params;
35
+ const out = await getGuide(name, page, permissionsOf(request.user, opts.permissionsOf));
36
+ if (out.status === 403) return reply.code(403).send({statusCode: 403, error: 'Forbidden', message: 'You cannot use this plugin.'});
37
+ if (out.status !== 200) return reply.code(404).send({statusCode: 404, error: 'Not Found', message: 'No such guide.'});
38
+ return out.guide;
39
+ };
40
+ fastify.get('/documentation/plugins/:name', signedIn, one);
41
+ fastify.get('/documentation/plugins/:name/:page', signedIn, one);
42
+ }
package/server/server.js CHANGED
@@ -487,6 +487,7 @@ const {apiTokensRoutes} = await import('./routes/api/api-tokens.js');
487
487
  const {apiEndpointsRoutes} = await import('./routes/api/api-endpoints.js');
488
488
  const {endpointsPublicRoutes} = await import('./routes/api/endpoints-public.js');
489
489
  const {sidebarRoutes} = await import('./routes/api/sidebar.js');
490
+ const {documentationRoutes} = await import('./routes/api/documentation.js');
490
491
  const { mediaRoutes } = await import('./routes/api/media.js');
491
492
  const { usersRoutes } = await import('./routes/api/users.js');
492
493
  const { pluginsRoutes } = await import('./routes/api/plugins.js');
@@ -525,6 +526,7 @@ await app.register(apiTokensRoutes, {prefix: '/api'});
525
526
  await app.register(apiEndpointsRoutes, {prefix: '/api'});
526
527
  await app.register(endpointsPublicRoutes, {prefix: '/api'});
527
528
  await app.register(sidebarRoutes, {prefix: '/api'});
529
+ await app.register(documentationRoutes, {prefix: '/api'});
528
530
  await app.register(mediaRoutes, { prefix: '/api' });
529
531
  await app.register(usersRoutes, { prefix: '/api' });
530
532
  await app.register(pluginsRoutes, { prefix: '/api' });
@@ -633,6 +635,16 @@ registerSidebarItem({folder: 'system', item: {source: 'Built in', text: 'Layouts
633
635
  registerSidebarItem({folder: 'system', item: {source: 'Built in', text: 'Plugins', url: '#/plugins', icon: 'package', permission: 'plugins', countUrl: '/api/plugins/_count', inventory: true}});
634
636
  registerSidebarItem({folder: 'system', item: {source: 'Built in', text: 'API Tokens', url: '#/api-tokens', icon: 'key', permission: 'api-tokens', countUrl: '/api/api-tokens/_count'}});
635
637
  registerSidebarItem({folder: 'system', item: {source: 'Built in', text: 'Search', url: '#/search', icon: 'search', permission: 'settings', countUrl: '/api/search/_count', inventory: true}});
638
+ // Documentation pages added after the sidebar menu was seeded (0.93.1). The menu is
639
+ // seeded once, so new pages reach existing sites only by registering here. The two
640
+ // sub-folders have no key in older menus; findFolder() falls back to their name.
641
+ registerSidebarItem({folder: 'Usage', item: {source: 'Built in', text: 'Collections & Forms', url: '#/docs/usage/collections', icon: 'database'}});
642
+ registerSidebarItem({folder: 'Usage', item: {source: 'Built in', text: 'Built-in Tools', url: '#/docs/usage/tools', icon: 'tool'}});
643
+ registerSidebarItem({folder: 'Usage', item: {source: 'Built in', text: 'Editions & Licences', url: '#/docs/usage/editions', icon: 'key'}});
644
+ registerSidebarItem({folder: 'API Reference', item: {source: 'Built in', text: 'Forms', url: '#/docs/api/forms', icon: 'layout'}});
645
+ registerSidebarItem({folder: 'API Reference', item: {source: 'Built in', text: 'Scaffold', url: '#/docs/api/scaffold', icon: 'package'}});
646
+ registerSidebarItem({folder: 'API Reference', item: {source: 'Built in', text: 'External API & Tokens', url: '#/docs/api/external', icon: 'key'}});
647
+ registerSidebarItem({folder: 'API Reference', item: {source: 'Built in', text: 'API Builder', url: '#/docs/api/builder', icon: 'code'}});
636
648
 
637
649
  // Core's notification sources, before plugins add theirs (0.80).
638
650
  const {registerCoreSources} = await import('./services/notification-sources.js');
@@ -55,6 +55,9 @@ const MAP = [
55
55
  ['usage-views', 'usage/views', 'Views'],
56
56
  ['usage-actions', 'usage/actions', 'Actions'],
57
57
  ['usage-cta-shortcode', 'usage/cta-shortcode', 'CTA Shortcode'],
58
+ ['usage-editions', 'usage/editions', 'Editions & Licences'],
59
+ ['usage-collections', 'usage/collections', 'Collections & Forms'],
60
+ ['usage-tools', 'usage/tools', 'Built-in Tools'],
58
61
  ['tutorial-crud', 'tutorials/crud', 'Building a CRUD App'],
59
62
  ['tutorial-plugin', 'tutorials/plugin', 'Writing a Plugin'],
60
63
  ['tutorial-forms', 'tutorials/forms', 'Form Follow-Up'],
@@ -72,7 +75,11 @@ const MAP = [
72
75
  ['api-plugins', 'api/plugins', 'Plugins API'],
73
76
  ['api-collections', 'api/collections', 'Collections API'],
74
77
  ['api-views', 'api/views', 'Views API'],
75
- ['api-actions', 'api/actions', 'Actions API']
78
+ ['api-actions', 'api/actions', 'Actions API'],
79
+ ['api-forms', 'api/forms', 'Forms API'],
80
+ ['api-scaffold', 'api/scaffold', 'Scaffold API'],
81
+ ['api-external', 'api/external', 'External API & Tokens'],
82
+ ['api-builder', 'api/builder', 'API Builder']
76
83
  ];
77
84
 
78
85
  // Admin-SPA hash routes and stale /resources/… paths don't resolve on the
@@ -134,6 +141,10 @@ function rewriteLinks(html) {
134
141
  for (const [from, to] of Object.entries(LINK_MAP)) {
135
142
  out = out.split(`href="${from}"`).join(`href="${to}"`);
136
143
  }
144
+ // Usage and API pages share their tail with the public handbook; plugin guides
145
+ // are admin-only (they depend on what is installed), so they open the admin.
146
+ out = out.replace(/href="#\/docs\/(usage|api)\/([a-z0-9-]+)"/g, 'href="/domma-docs/$1/$2"');
147
+ out = out.replace(/href="#\/docs\/plugins([^"]*)"/g, 'href="/admin#/docs/plugins$1"');
137
148
  // Any remaining /resources/… link has no doc equivalent - unwrap to text.
138
149
  out = out.replace(/<a\b[^>]*\shref="\/resources\/[^"]*"[^>]*>([\s\S]*?)<\/a>/gi, '$1');
139
150
  return out;
@@ -347,7 +358,7 @@ export async function renderDocPage(docPath, opts = {}) {
347
358
  }
348
359
 
349
360
  /**
350
- * Every valid doc path (home + 29 leaves + 3 section landings). The Components
361
+ * Every valid doc path (home + every leaf + 3 section landings). The Components
351
362
  * landing is the 'components' leaf, already in MAP. `renderDocPage` returning
352
363
  * null is the authoritative miss; this is an enumeration aid (e.g. sitemap).
353
364
  *