odac 0.9.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.
- package/.editorconfig +21 -0
- package/.github/workflows/auto-pr-description.yml +49 -0
- package/.github/workflows/release.yml +32 -0
- package/.github/workflows/test-coverage.yml +58 -0
- package/.husky/pre-commit +2 -0
- package/.kiro/steering/code-style.md +56 -0
- package/.kiro/steering/product.md +20 -0
- package/.kiro/steering/structure.md +77 -0
- package/.kiro/steering/tech.md +87 -0
- package/.prettierrc +10 -0
- package/.releaserc.js +134 -0
- package/AGENTS.md +84 -0
- package/CHANGELOG.md +181 -0
- package/CODE_OF_CONDUCT.md +83 -0
- package/CONTRIBUTING.md +63 -0
- package/LICENSE +661 -0
- package/README.md +57 -0
- package/SECURITY.md +26 -0
- package/bin/candy +10 -0
- package/bin/candypack +10 -0
- package/cli/index.js +3 -0
- package/cli/src/Cli.js +348 -0
- package/cli/src/Connector.js +93 -0
- package/cli/src/Monitor.js +416 -0
- package/core/Candy.js +87 -0
- package/core/Commands.js +239 -0
- package/core/Config.js +1094 -0
- package/core/Lang.js +52 -0
- package/core/Log.js +43 -0
- package/core/Process.js +26 -0
- package/docs/backend/01-overview/01-whats-in-the-candy-box.md +9 -0
- package/docs/backend/01-overview/02-super-handy-helper-functions.md +9 -0
- package/docs/backend/01-overview/03-development-server.md +79 -0
- package/docs/backend/02-structure/01-typical-project-layout.md +39 -0
- package/docs/backend/03-config/00-configuration-overview.md +214 -0
- package/docs/backend/03-config/01-database-connection.md +60 -0
- package/docs/backend/03-config/02-static-route-mapping-optional.md +20 -0
- package/docs/backend/03-config/03-request-timeout.md +11 -0
- package/docs/backend/03-config/04-environment-variables.md +227 -0
- package/docs/backend/03-config/05-early-hints.md +352 -0
- package/docs/backend/04-routing/01-basic-page-routes.md +28 -0
- package/docs/backend/04-routing/02-controller-less-view-routes.md +43 -0
- package/docs/backend/04-routing/03-api-and-data-routes.md +20 -0
- package/docs/backend/04-routing/04-authentication-aware-routes.md +48 -0
- package/docs/backend/04-routing/05-advanced-routing.md +14 -0
- package/docs/backend/04-routing/06-error-pages.md +101 -0
- package/docs/backend/04-routing/07-cron-jobs.md +149 -0
- package/docs/backend/05-controllers/01-how-to-build-a-controller.md +17 -0
- package/docs/backend/05-controllers/02-your-trusty-candy-assistant.md +20 -0
- package/docs/backend/05-controllers/03-controller-classes.md +93 -0
- package/docs/backend/05-forms/01-custom-forms.md +395 -0
- package/docs/backend/05-forms/02-automatic-database-insert.md +297 -0
- package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +96 -0
- package/docs/backend/06-request-and-response/02-sending-a-response-replying-to-the-user.md +40 -0
- package/docs/backend/07-views/01-the-view-directory.md +73 -0
- package/docs/backend/07-views/02-rendering-a-view.md +179 -0
- package/docs/backend/07-views/03-template-syntax.md +181 -0
- package/docs/backend/07-views/03-variables.md +328 -0
- package/docs/backend/07-views/04-request-data.md +231 -0
- package/docs/backend/07-views/05-conditionals.md +290 -0
- package/docs/backend/07-views/06-loops.md +353 -0
- package/docs/backend/07-views/07-translations.md +358 -0
- package/docs/backend/07-views/08-backend-javascript.md +398 -0
- package/docs/backend/07-views/09-comments.md +297 -0
- package/docs/backend/08-database/01-database-connection.md +99 -0
- package/docs/backend/08-database/02-using-mysql.md +322 -0
- package/docs/backend/09-validation/01-the-validator-service.md +424 -0
- package/docs/backend/10-authentication/01-user-logins-with-authjs.md +53 -0
- package/docs/backend/10-authentication/02-foiling-villains-with-csrf-protection.md +55 -0
- package/docs/backend/10-authentication/03-register.md +134 -0
- package/docs/backend/10-authentication/04-candy-register-forms.md +676 -0
- package/docs/backend/10-authentication/05-session-management.md +159 -0
- package/docs/backend/10-authentication/06-candy-login-forms.md +596 -0
- package/docs/backend/11-mail/01-the-mail-service.md +42 -0
- package/docs/backend/12-streaming/01-streaming-overview.md +300 -0
- package/docs/backend/13-utilities/01-candy-var.md +504 -0
- package/docs/frontend/01-overview/01-introduction.md +146 -0
- package/docs/frontend/02-ajax-navigation/01-quick-start.md +608 -0
- package/docs/frontend/02-ajax-navigation/02-configuration.md +370 -0
- package/docs/frontend/02-ajax-navigation/03-advanced-usage.md +519 -0
- package/docs/frontend/03-forms/01-form-handling.md +420 -0
- package/docs/frontend/04-api-requests/01-get-post.md +443 -0
- package/docs/frontend/05-streaming/01-client-streaming.md +163 -0
- package/docs/index.json +452 -0
- package/docs/server/01-installation/01-quick-install.md +19 -0
- package/docs/server/01-installation/02-manual-installation-via-npm.md +9 -0
- package/docs/server/02-get-started/01-core-concepts.md +7 -0
- package/docs/server/02-get-started/02-basic-commands.md +57 -0
- package/docs/server/02-get-started/03-cli-reference.md +276 -0
- package/docs/server/02-get-started/04-cli-quick-reference.md +102 -0
- package/docs/server/03-service/01-start-a-new-service.md +57 -0
- package/docs/server/03-service/02-delete-a-service.md +48 -0
- package/docs/server/04-web/01-create-a-website.md +36 -0
- package/docs/server/04-web/02-list-websites.md +9 -0
- package/docs/server/04-web/03-delete-a-website.md +29 -0
- package/docs/server/05-subdomain/01-create-a-subdomain.md +32 -0
- package/docs/server/05-subdomain/02-list-subdomains.md +33 -0
- package/docs/server/05-subdomain/03-delete-a-subdomain.md +41 -0
- package/docs/server/06-ssl/01-renew-an-ssl-certificate.md +34 -0
- package/docs/server/07-mail/01-create-a-mail-account.md +23 -0
- package/docs/server/07-mail/02-delete-a-mail-account.md +20 -0
- package/docs/server/07-mail/03-list-mail-accounts.md +20 -0
- package/docs/server/07-mail/04-change-account-password.md +23 -0
- package/eslint.config.mjs +120 -0
- package/framework/index.js +4 -0
- package/framework/src/Auth.js +309 -0
- package/framework/src/Candy.js +81 -0
- package/framework/src/Config.js +79 -0
- package/framework/src/Env.js +60 -0
- package/framework/src/Lang.js +57 -0
- package/framework/src/Mail.js +83 -0
- package/framework/src/Mysql.js +575 -0
- package/framework/src/Request.js +301 -0
- package/framework/src/Route/Cron.js +128 -0
- package/framework/src/Route/Internal.js +439 -0
- package/framework/src/Route.js +455 -0
- package/framework/src/Server.js +15 -0
- package/framework/src/Stream.js +163 -0
- package/framework/src/Token.js +37 -0
- package/framework/src/Validator.js +271 -0
- package/framework/src/Var.js +211 -0
- package/framework/src/View/EarlyHints.js +190 -0
- package/framework/src/View/Form.js +600 -0
- package/framework/src/View.js +513 -0
- package/framework/web/candy.js +838 -0
- package/jest.config.js +22 -0
- package/locale/de-DE.json +80 -0
- package/locale/en-US.json +79 -0
- package/locale/es-ES.json +80 -0
- package/locale/fr-FR.json +80 -0
- package/locale/pt-BR.json +80 -0
- package/locale/ru-RU.json +80 -0
- package/locale/tr-TR.json +85 -0
- package/locale/zh-CN.json +80 -0
- package/package.json +86 -0
- package/server/index.js +5 -0
- package/server/src/Api.js +88 -0
- package/server/src/DNS.js +940 -0
- package/server/src/Hub.js +535 -0
- package/server/src/Mail.js +571 -0
- package/server/src/SSL.js +180 -0
- package/server/src/Server.js +27 -0
- package/server/src/Service.js +248 -0
- package/server/src/Subdomain.js +64 -0
- package/server/src/Web/Firewall.js +170 -0
- package/server/src/Web/Proxy.js +134 -0
- package/server/src/Web.js +451 -0
- package/server/src/mail/imap.js +1091 -0
- package/server/src/mail/server.js +32 -0
- package/server/src/mail/smtp.js +786 -0
- package/test/cli/Cli.test.js +36 -0
- package/test/core/Candy.test.js +234 -0
- package/test/core/Commands.test.js +538 -0
- package/test/core/Config.test.js +1435 -0
- package/test/core/Lang.test.js +250 -0
- package/test/core/Process.test.js +156 -0
- package/test/framework/Route.test.js +239 -0
- package/test/framework/View/EarlyHints.test.js +282 -0
- package/test/scripts/check-coverage.js +132 -0
- package/test/server/Api.test.js +647 -0
- package/test/server/Client.test.js +338 -0
- package/test/server/DNS.test.js +2050 -0
- package/test/server/DNS.test.js.bak +2084 -0
- package/test/server/Log.test.js +73 -0
- package/test/server/Mail.account.test_.js +460 -0
- package/test/server/Mail.init.test_.js +411 -0
- package/test/server/Mail.test_.js +1340 -0
- package/test/server/SSL.test_.js +1491 -0
- package/test/server/Server.test.js +765 -0
- package/test/server/Service.test_.js +1127 -0
- package/test/server/Subdomain.test.js +440 -0
- package/test/server/Web/Firewall.test.js +175 -0
- package/test/server/Web.test_.js +1562 -0
- package/test/server/__mocks__/acme-client.js +17 -0
- package/test/server/__mocks__/bcrypt.js +50 -0
- package/test/server/__mocks__/child_process.js +389 -0
- package/test/server/__mocks__/crypto.js +432 -0
- package/test/server/__mocks__/fs.js +450 -0
- package/test/server/__mocks__/globalCandy.js +227 -0
- package/test/server/__mocks__/http-proxy.js +105 -0
- package/test/server/__mocks__/http.js +575 -0
- package/test/server/__mocks__/https.js +272 -0
- package/test/server/__mocks__/index.js +249 -0
- package/test/server/__mocks__/mail/server.js +100 -0
- package/test/server/__mocks__/mail/smtp.js +31 -0
- package/test/server/__mocks__/mailparser.js +81 -0
- package/test/server/__mocks__/net.js +369 -0
- package/test/server/__mocks__/node-forge.js +328 -0
- package/test/server/__mocks__/os.js +320 -0
- package/test/server/__mocks__/path.js +291 -0
- package/test/server/__mocks__/selfsigned.js +8 -0
- package/test/server/__mocks__/server/src/mail/server.js +100 -0
- package/test/server/__mocks__/server/src/mail/smtp.js +31 -0
- package/test/server/__mocks__/smtp-server.js +106 -0
- package/test/server/__mocks__/sqlite3.js +394 -0
- package/test/server/__mocks__/testFactories.js +299 -0
- package/test/server/__mocks__/testHelpers.js +363 -0
- package/test/server/__mocks__/tls.js +229 -0
- package/watchdog/index.js +3 -0
- package/watchdog/src/Watchdog.js +156 -0
- package/web/config.json +5 -0
- package/web/controller/page/about.js +27 -0
- package/web/controller/page/index.js +34 -0
- package/web/package.json +18 -0
- package/web/public/assets/css/style.css +1835 -0
- package/web/public/assets/js/app.js +96 -0
- package/web/route/www.js +19 -0
- package/web/skeleton/main.html +22 -0
- package/web/view/content/about.html +65 -0
- package/web/view/content/home.html +205 -0
- package/web/view/footer/main.html +11 -0
- package/web/view/head/main.html +5 -0
- package/web/view/header/main.html +14 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
## 🔐 Authentication-Aware Routes
|
|
2
|
+
|
|
3
|
+
These methods let you define routes that require authentication. Only logged-in users can access these routes.
|
|
4
|
+
|
|
5
|
+
#### `auth.page(path, controller)`
|
|
6
|
+
Defines a page route that requires authentication.
|
|
7
|
+
|
|
8
|
+
```javascript
|
|
9
|
+
// Only authenticated users can access the dashboard
|
|
10
|
+
Candy.Route.auth.page('/dashboard', 'dashboard.index');
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
#### `auth.page(path, viewConfig)`
|
|
14
|
+
Defines a controller-less page route that requires authentication.
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
// Only authenticated users can see this view
|
|
18
|
+
Candy.Route.auth.page('/profile', {
|
|
19
|
+
skeleton: 'main',
|
|
20
|
+
head: 'profile.head',
|
|
21
|
+
content: 'profile',
|
|
22
|
+
script: 'profile'
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
#### `auth.get(path, controller, options)`
|
|
27
|
+
Defines a GET route that requires authentication.
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
// API endpoint for authenticated users only
|
|
31
|
+
Candy.Route.auth.get('/api/user/profile', 'api.user.profile');
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
#### `auth.post(path, controller, options)`
|
|
35
|
+
Defines a POST route that requires authentication.
|
|
36
|
+
|
|
37
|
+
```javascript
|
|
38
|
+
// Only authenticated users can update their profile
|
|
39
|
+
Candy.Route.auth.post('/api/user/update', 'api.user.update');
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
#### CSRF Token Protection
|
|
43
|
+
By default, all POST and GET routes have CSRF token protection enabled. You can disable it with the `token` option:
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
// Disable CSRF token check for this route
|
|
47
|
+
Candy.Route.auth.post('/api/webhook', 'api.webhook', {token: false});
|
|
48
|
+
```
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
## 🛠️ Advanced Routing
|
|
2
|
+
|
|
3
|
+
#### `set(type, path, controller, options)`
|
|
4
|
+
This is the powerful base method that all other routing methods use internally. You can use it to create routes for any custom type.
|
|
5
|
+
|
|
6
|
+
- `type`: A string defining the route type (e.g., `page`, `post`, `#page` for authenticated pages, etc.).
|
|
7
|
+
|
|
8
|
+
```javascript
|
|
9
|
+
// This is equivalent to Candy.Route.post('/register', 'auth.register')
|
|
10
|
+
Candy.Route.set('post', '/register', 'auth.register');
|
|
11
|
+
|
|
12
|
+
// This creates an authenticated page route
|
|
13
|
+
Candy.Route.set('#page', '/account', 'account.settings');
|
|
14
|
+
```
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
## 🚨 Error Pages
|
|
2
|
+
|
|
3
|
+
CandyPack framework provides built-in error handling with customizable error pages for different HTTP status codes. You can define custom error pages to provide a better user experience when things go wrong.
|
|
4
|
+
|
|
5
|
+
#### `error(statusCode, controller)`
|
|
6
|
+
Maps HTTP error status codes to custom controller handlers. This allows you to create branded error pages instead of showing generic browser error messages.
|
|
7
|
+
|
|
8
|
+
- `statusCode`: The HTTP status code to handle (e.g., `404`, `500`).
|
|
9
|
+
- `controller`: The name of the controller file to handle this error.
|
|
10
|
+
|
|
11
|
+
```javascript
|
|
12
|
+
// Custom 404 Not Found page
|
|
13
|
+
Candy.Route.error(404, 'errors/not-found');
|
|
14
|
+
|
|
15
|
+
// Custom 500 Internal Server Error page
|
|
16
|
+
Candy.Route.error(500, 'errors/server-error');
|
|
17
|
+
|
|
18
|
+
// Custom 403 Forbidden page
|
|
19
|
+
Candy.Route.error(403, 'errors/forbidden');
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
#### Common Error Status Codes
|
|
23
|
+
|
|
24
|
+
- **404 Not Found**: Page or resource doesn't exist
|
|
25
|
+
- **403 Forbidden**: Access denied to the resource
|
|
26
|
+
- **500 Internal Server Error**: Server-side error occurred
|
|
27
|
+
- **401 Unauthorized**: Authentication required
|
|
28
|
+
- **400 Bad Request**: Invalid request format
|
|
29
|
+
|
|
30
|
+
#### Error Controller Example
|
|
31
|
+
|
|
32
|
+
Create error controllers in your `controller/errors/` directory:
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
// controller/errors/not-found.js
|
|
36
|
+
module.exports = function() {
|
|
37
|
+
Candy.response.status(404);
|
|
38
|
+
return Candy.view('errors/404', {
|
|
39
|
+
title: 'Page Not Found',
|
|
40
|
+
message: 'The page you are looking for could not be found.'
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
// controller/errors/server-error.js
|
|
47
|
+
module.exports = function() {
|
|
48
|
+
Candy.response.status(500);
|
|
49
|
+
return Candy.view('errors/500', {
|
|
50
|
+
title: 'Server Error',
|
|
51
|
+
message: 'Something went wrong on our end. Please try again later.'
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### Error Views
|
|
57
|
+
|
|
58
|
+
Create corresponding view templates in your `view/errors/` directory:
|
|
59
|
+
|
|
60
|
+
```html
|
|
61
|
+
<!-- view/errors/404.html -->
|
|
62
|
+
<!DOCTYPE html>
|
|
63
|
+
<html>
|
|
64
|
+
<head>
|
|
65
|
+
<title>{{title}}</title>
|
|
66
|
+
</head>
|
|
67
|
+
<body>
|
|
68
|
+
<h1>404 - Page Not Found</h1>
|
|
69
|
+
<p>{{message}}</p>
|
|
70
|
+
<a href="/">Go back to homepage</a>
|
|
71
|
+
</body>
|
|
72
|
+
</html>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### Default Error Handling
|
|
76
|
+
|
|
77
|
+
If no custom error page is defined, CandyPack will fall back to its built-in error responses. It's recommended to at least define custom 404 and 500 error pages for a professional user experience.
|
|
78
|
+
|
|
79
|
+
#### Error Context
|
|
80
|
+
|
|
81
|
+
Error controllers receive the same Candy context as regular controllers, allowing you to:
|
|
82
|
+
|
|
83
|
+
- Access request information (`Candy.request`)
|
|
84
|
+
- Use database connections (`Candy.db`)
|
|
85
|
+
- Render views with data (`Candy.view`)
|
|
86
|
+
- Redirect users (`Candy.redirect`)
|
|
87
|
+
- Log error details for debugging
|
|
88
|
+
|
|
89
|
+
```javascript
|
|
90
|
+
// controller/errors/server-error.js
|
|
91
|
+
module.exports = function() {
|
|
92
|
+
// Log the error for debugging
|
|
93
|
+
console.error('Server error occurred:', Candy.request.url);
|
|
94
|
+
|
|
95
|
+
Candy.response.status(500);
|
|
96
|
+
return Candy.view('errors/500', {
|
|
97
|
+
title: 'Oops! Something went wrong',
|
|
98
|
+
supportEmail: 'support@yoursite.com'
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
```
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Cron Jobs
|
|
2
|
+
|
|
3
|
+
The CandyPack framework provides a built-in cron system for running automated tasks. This system checks every minute and executes jobs based on specified conditions.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
Use the `Candy.Route.cron()` method to define cron jobs:
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
// With controller file
|
|
11
|
+
Candy.Route.cron('backup').everyDay(1) // Runs every day
|
|
12
|
+
|
|
13
|
+
// With direct function
|
|
14
|
+
Candy.Route.cron(() => {
|
|
15
|
+
console.log('Task executed!')
|
|
16
|
+
}).everyHour(2) // Runs every 2 hours
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Controller Files
|
|
20
|
+
|
|
21
|
+
Controller files for cron jobs are created in the `controller/cron/` directory:
|
|
22
|
+
|
|
23
|
+
```javascript
|
|
24
|
+
// controller/cron/backup.js
|
|
25
|
+
module.exports = () => {
|
|
26
|
+
console.log('Backup process started')
|
|
27
|
+
// Backup code...
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
For module-based organization:
|
|
32
|
+
|
|
33
|
+
```javascript
|
|
34
|
+
// controller/admin/cron/cleanup.js
|
|
35
|
+
module.exports = () => {
|
|
36
|
+
console.log('Cleanup process')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Usage
|
|
40
|
+
Candy.Route.cron('admin.cleanup').everyDay(1)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Direct Function Usage
|
|
44
|
+
|
|
45
|
+
You can also define cron jobs with inline functions:
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
// Simple inline function
|
|
49
|
+
Candy.Route.cron(() => console.log('Simple task running')).everyMinute(5)
|
|
50
|
+
|
|
51
|
+
// Async function
|
|
52
|
+
Candy.Route.cron(async () => {
|
|
53
|
+
const data = await fetchSomeData()
|
|
54
|
+
console.log('Async task completed', data)
|
|
55
|
+
}).everyHour(1)
|
|
56
|
+
|
|
57
|
+
// Function with parameters
|
|
58
|
+
const cleanupTask = (directory) => {
|
|
59
|
+
console.log(`Cleaning up ${directory}`)
|
|
60
|
+
// Cleanup logic...
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
Candy.Route.cron(() => cleanupTask('/tmp')).everyDay(1)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Time Conditions
|
|
67
|
+
|
|
68
|
+
### Specific Time Values
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
Candy.Route.cron('task')
|
|
72
|
+
|
|
73
|
+
// Minute (0-59)
|
|
74
|
+
.minute(30) // At 30th minute
|
|
75
|
+
|
|
76
|
+
// Hour (0-23)
|
|
77
|
+
.hour(14) // At 14:00
|
|
78
|
+
|
|
79
|
+
// Day (1-31)
|
|
80
|
+
.day(15) // On the 15th of the month
|
|
81
|
+
|
|
82
|
+
// Week day (0-6, 0=Sunday)
|
|
83
|
+
.weekDay(1) // On Monday
|
|
84
|
+
|
|
85
|
+
// Month (1-12)
|
|
86
|
+
.month(6) // In June
|
|
87
|
+
|
|
88
|
+
// Year
|
|
89
|
+
.year(2024) // In 2024
|
|
90
|
+
|
|
91
|
+
// Year day (1-365)
|
|
92
|
+
.yearDay(100) // On the 100th day of the year
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Periodic Execution
|
|
96
|
+
|
|
97
|
+
```javascript
|
|
98
|
+
Candy.Route.cron('periodic')
|
|
99
|
+
|
|
100
|
+
// Every N minutes
|
|
101
|
+
.everyMinute(5) // Every 5 minutes
|
|
102
|
+
|
|
103
|
+
// Every N hours
|
|
104
|
+
.everyHour(3) // Every 3 hours
|
|
105
|
+
|
|
106
|
+
// Every N days
|
|
107
|
+
.everyDay(2) // Every 2 days
|
|
108
|
+
|
|
109
|
+
// Every N weeks
|
|
110
|
+
.everyWeekDay(1) // Every week
|
|
111
|
+
|
|
112
|
+
// Every N months
|
|
113
|
+
.everyMonth(2) // Every 2 months
|
|
114
|
+
|
|
115
|
+
// Every N years
|
|
116
|
+
.everyYear(1) // Every year
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Combination Usage
|
|
120
|
+
|
|
121
|
+
You can combine multiple conditions:
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
// Every day at 14:30
|
|
125
|
+
Candy.Route.cron('daily-report')
|
|
126
|
+
.hour(14)
|
|
127
|
+
.minute(30)
|
|
128
|
+
|
|
129
|
+
// Mondays at 09:00
|
|
130
|
+
Candy.Route.cron('weekly-task')
|
|
131
|
+
.weekDay(1)
|
|
132
|
+
.hour(9)
|
|
133
|
+
.minute(0)
|
|
134
|
+
|
|
135
|
+
// First day of every month at midnight
|
|
136
|
+
Candy.Route.cron('monthly-cleanup')
|
|
137
|
+
.day(1)
|
|
138
|
+
.hour(0)
|
|
139
|
+
.minute(0)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Important Notes
|
|
143
|
+
|
|
144
|
+
- The cron system checks every minute
|
|
145
|
+
- Jobs run at the first suitable time after their last update
|
|
146
|
+
- If the same job is defined multiple times, the last definition takes precedence
|
|
147
|
+
- Controller files are re-required on each execution
|
|
148
|
+
- Inline functions are stored in memory and executed directly
|
|
149
|
+
- If a job fails, it stops but the system continues
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
## 🏗️ How to Build a Controller
|
|
2
|
+
|
|
3
|
+
A controller is just a JavaScript module that exports a function. This function automatically gets the magical `Candy` context object we talked about in the overview.
|
|
4
|
+
|
|
5
|
+
#### A Simple "Hello World" Controller
|
|
6
|
+
|
|
7
|
+
Check out this basic example from `controller/page/index.js`:
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
// This function is our controller!
|
|
11
|
+
module.exports = function (Candy) {
|
|
12
|
+
// It simply returns a string.
|
|
13
|
+
return 'Welcome to my awesome CandyPack server!'
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
This little guy is responsible for handling the homepage route (`/`). When it runs, it just sends a simple string back to the user's browser.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
## 🤝 Your trusty `Candy` Assistant
|
|
2
|
+
|
|
3
|
+
Remember the `Candy` object? It's your best friend inside a controller. It's passed to your controller function and gives you all the tools you need for the current request.
|
|
4
|
+
|
|
5
|
+
#### Awesome Services at Your Fingertips
|
|
6
|
+
|
|
7
|
+
* `Candy.Request`: Info about the user's request.
|
|
8
|
+
* `Candy.View`: Renders your HTML pages.
|
|
9
|
+
* `Candy.Auth`: Manages user logins.
|
|
10
|
+
* `Candy.Token`: Protects your forms.
|
|
11
|
+
* `Candy.Lang`: Helps with different languages.
|
|
12
|
+
|
|
13
|
+
#### Handy Helper Functions
|
|
14
|
+
|
|
15
|
+
* `Candy.return(data)`: Send back a response.
|
|
16
|
+
* `Candy.direct(url)`: Redirect the user to a new page.
|
|
17
|
+
* `Candy.cookie(key, value)`: Set a browser cookie.
|
|
18
|
+
* `Candy.validator()`: Check user input easily.
|
|
19
|
+
|
|
20
|
+
With controllers and the `Candy` object, you have everything you need to start building powerful application logic!
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
## 🎓 Controller Classes
|
|
2
|
+
|
|
3
|
+
While simple function exports work great for basic controllers, you can also organize your code using classes. This is especially useful when you want to share logic between multiple methods or keep related functionality together.
|
|
4
|
+
|
|
5
|
+
#### Creating a Controller Class
|
|
6
|
+
|
|
7
|
+
A controller class receives the `Candy` object in its constructor, giving you access to all services throughout your class methods:
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
// controller/User.js
|
|
11
|
+
class User {
|
|
12
|
+
constructor(Candy) {
|
|
13
|
+
this.Candy = Candy
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async getProfile() {
|
|
17
|
+
const user = await this.Candy.Auth.user()
|
|
18
|
+
return this.Candy.return({
|
|
19
|
+
success: true,
|
|
20
|
+
user: user
|
|
21
|
+
})
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async updateProfile() {
|
|
25
|
+
const validator = this.Candy.validator()
|
|
26
|
+
validator.post('name').required().min(3)
|
|
27
|
+
validator.post('email').required().email()
|
|
28
|
+
|
|
29
|
+
if (await validator.error()) {
|
|
30
|
+
return validator.result()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const name = await this.Candy.request('name')
|
|
34
|
+
const email = await this.Candy.request('email')
|
|
35
|
+
|
|
36
|
+
// Update user in database
|
|
37
|
+
await this.Candy.Mysql.query('UPDATE users SET name = ?, email = ? WHERE id = ?', [
|
|
38
|
+
name,
|
|
39
|
+
email,
|
|
40
|
+
this.Candy.Auth.user().id
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
return this.Candy.return({
|
|
44
|
+
success: true,
|
|
45
|
+
message: 'Profile updated successfully'
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = User
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
#### Using Controller Classes in Routes
|
|
54
|
+
|
|
55
|
+
Once you've created a controller class, you can use it in your routes just like any other controller:
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
// route/www.js
|
|
59
|
+
Candy.Route.buff = 'www'
|
|
60
|
+
|
|
61
|
+
// Access class methods using dot notation
|
|
62
|
+
Candy.Route.get('/profile', 'User.getProfile')
|
|
63
|
+
Candy.Route.post('/profile/update', 'User.updateProfile')
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
#### Accessing Classes in Controllers
|
|
67
|
+
|
|
68
|
+
Controller classes are automatically instantiated for each request and attached to the `Candy` object. You can access them from any controller:
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
module.exports = async function (Candy) {
|
|
72
|
+
// Access your User class
|
|
73
|
+
const profile = await Candy.User.getProfile()
|
|
74
|
+
|
|
75
|
+
return Candy.return(profile)
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
#### Benefits of Controller Classes
|
|
80
|
+
|
|
81
|
+
- **Organization**: Group related methods together
|
|
82
|
+
- **Reusability**: Share logic between different routes
|
|
83
|
+
- **Maintainability**: Easier to manage complex controllers
|
|
84
|
+
- **Context**: The `Candy` object is always available via `this.Candy`
|
|
85
|
+
|
|
86
|
+
#### Class vs Function Controllers
|
|
87
|
+
|
|
88
|
+
Both approaches work perfectly fine. Use what makes sense for your project:
|
|
89
|
+
|
|
90
|
+
- **Functions**: Great for simple, single-purpose controllers
|
|
91
|
+
- **Classes**: Better for complex logic with multiple related methods
|
|
92
|
+
|
|
93
|
+
The framework automatically detects whether your export is a class or a function and handles it accordingly.
|