odac 0.9.0 → 1.0.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/.github/workflows/auto-pr-description.yml +0 -2
- package/.github/workflows/codeql.yml +46 -0
- package/.github/workflows/release.yml +13 -6
- package/.github/workflows/test-coverage.yml +10 -9
- package/.releaserc.js +9 -6
- package/CHANGELOG.md +62 -150
- package/CODE_OF_CONDUCT.md +1 -1
- package/CONTRIBUTING.md +8 -8
- package/LICENSE +21 -661
- package/README.md +12 -12
- package/SECURITY.md +4 -4
- package/bin/odac.js +101 -0
- package/{framework/web/candy.js → client/odac.js} +310 -44
- package/docs/backend/01-overview/{01-whats-in-the-candy-box.md → 01-whats-in-the-odac-box.md} +4 -2
- package/docs/backend/01-overview/02-super-handy-helper-functions.md +29 -1
- package/docs/backend/01-overview/03-development-server.md +11 -11
- package/docs/backend/02-structure/01-typical-project-layout.md +4 -4
- package/docs/backend/03-config/00-configuration-overview.md +6 -6
- package/docs/backend/03-config/01-database-connection.md +1 -1
- package/docs/backend/03-config/02-static-route-mapping-optional.md +4 -4
- package/docs/backend/03-config/04-environment-variables.md +20 -20
- package/docs/backend/03-config/05-early-hints.md +4 -4
- package/docs/backend/04-routing/01-basic-page-routes.md +4 -4
- package/docs/backend/04-routing/02-controller-less-view-routes.md +5 -5
- package/docs/backend/04-routing/03-api-and-data-routes.md +3 -3
- package/docs/backend/04-routing/04-authentication-aware-routes.md +5 -5
- package/docs/backend/04-routing/05-advanced-routing.md +3 -3
- package/docs/backend/04-routing/06-error-pages.md +17 -17
- package/docs/backend/04-routing/07-cron-jobs.md +13 -13
- package/docs/backend/04-routing/08-middleware.md +214 -0
- package/docs/backend/04-routing/09-websocket-auth-middleware.md +292 -0
- package/docs/backend/04-routing/09-websocket-examples.md +381 -0
- package/docs/backend/04-routing/09-websocket-quick-reference.md +211 -0
- package/docs/backend/04-routing/09-websocket.md +298 -0
- package/docs/backend/05-controllers/01-how-to-build-a-controller.md +3 -3
- package/docs/backend/05-controllers/02-your-trusty-odac-assistant.md +41 -0
- package/docs/backend/05-controllers/03-controller-classes.md +19 -19
- package/docs/backend/05-forms/01-custom-forms.md +114 -114
- package/docs/backend/05-forms/02-automatic-database-insert.md +82 -82
- package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +26 -26
- package/docs/backend/06-request-and-response/02-sending-a-response-replying-to-the-user.md +10 -10
- package/docs/backend/07-views/01-the-view-directory.md +1 -1
- package/docs/backend/07-views/02-rendering-a-view.md +22 -22
- package/docs/backend/07-views/03-template-syntax.md +52 -52
- package/docs/backend/07-views/03-variables.md +84 -84
- package/docs/backend/07-views/04-request-data.md +57 -57
- package/docs/backend/07-views/05-conditionals.md +78 -78
- package/docs/backend/07-views/06-loops.md +114 -114
- package/docs/backend/07-views/07-translations.md +66 -66
- package/docs/backend/07-views/08-backend-javascript.md +103 -103
- package/docs/backend/07-views/09-comments.md +71 -71
- package/docs/backend/08-database/01-database-connection.md +8 -8
- package/docs/backend/08-database/02-using-mysql.md +49 -49
- package/docs/backend/09-validation/01-the-validator-service.md +38 -38
- package/docs/backend/10-authentication/01-user-logins-with-authjs.md +15 -15
- package/docs/backend/10-authentication/02-foiling-villains-with-csrf-protection.md +10 -10
- package/docs/backend/10-authentication/03-register.md +12 -12
- package/docs/backend/10-authentication/{04-candy-register-forms.md → 04-odac-register-forms.md} +141 -141
- package/docs/backend/10-authentication/05-session-management.md +10 -10
- package/docs/backend/10-authentication/{06-candy-login-forms.md → 06-odac-login-forms.md} +125 -125
- package/docs/backend/11-mail/01-the-mail-service.md +5 -5
- package/docs/backend/12-streaming/01-streaming-overview.md +96 -54
- package/docs/backend/13-utilities/{01-candy-var.md → 01-odac-var.md} +109 -109
- package/docs/frontend/01-overview/01-introduction.md +30 -30
- package/docs/frontend/02-ajax-navigation/01-quick-start.md +45 -45
- package/docs/frontend/02-ajax-navigation/02-configuration.md +14 -14
- package/docs/frontend/02-ajax-navigation/03-advanced-usage.md +36 -36
- package/docs/frontend/03-forms/01-form-handling.md +32 -32
- package/docs/frontend/04-api-requests/01-get-post.md +33 -33
- package/docs/frontend/05-streaming/01-client-streaming.md +15 -15
- package/docs/frontend/06-websocket/00-overview.md +76 -0
- package/docs/frontend/06-websocket/01-websocket-client.md +139 -0
- package/docs/frontend/06-websocket/02-shared-websocket.md +149 -0
- package/docs/index.json +49 -11
- package/eslint.config.mjs +6 -6
- package/{framework/index.js → index.js} +1 -1
- package/package.json +14 -39
- package/{framework/src → src}/Auth.js +59 -59
- package/{framework/src → src}/Config.js +3 -3
- package/{framework/src → src}/Lang.js +7 -7
- package/{framework/src → src}/Mail.js +5 -5
- package/{framework/src → src}/Mysql.js +42 -42
- package/src/Odac.js +112 -0
- package/{framework/src → src}/Request.js +38 -36
- package/{framework/src → src}/Route/Internal.js +116 -116
- package/src/Route/Middleware.js +75 -0
- package/src/Route.js +621 -0
- package/src/Server.js +22 -0
- package/{framework/src → src}/Stream.js +11 -3
- package/{framework/src → src}/Validator.js +21 -21
- package/{framework/src → src}/Var.js +5 -5
- package/{framework/src → src}/View/EarlyHints.js +1 -1
- package/{framework/src → src}/View/Form.js +69 -69
- package/{framework/src → src}/View.js +78 -81
- package/src/WebSocket.js +403 -0
- package/template/config.json +5 -0
- package/{web → template}/controller/page/about.js +6 -6
- package/{web → template}/controller/page/index.js +9 -9
- package/{web → template}/package.json +4 -5
- package/{web → template}/public/assets/css/style.css +4 -4
- package/{web → template}/public/assets/js/app.js +6 -6
- package/{web → template}/route/www.js +6 -6
- package/{web → template}/skeleton/main.html +1 -1
- package/{web → template}/view/content/about.html +5 -5
- package/{web → template}/view/content/home.html +12 -12
- package/template/view/footer/main.html +11 -0
- package/{web → template}/view/head/main.html +1 -1
- package/{web → template}/view/header/main.html +2 -2
- package/test/core/Candy.test.js +58 -58
- package/test/core/Commands.test.js +7 -7
- package/test/core/Config.test.js +82 -85
- package/test/core/Lang.test.js +2 -2
- package/test/core/Process.test.js +6 -6
- package/test/framework/Route.test.js +56 -37
- package/test/framework/View/EarlyHints.test.js +2 -2
- package/test/framework/WebSocket.test.js +100 -0
- package/test/framework/middleware.test.js +85 -0
- package/test/server/Api.test.js +31 -31
- package/test/server/DNS.test.js +11 -11
- package/test/server/Hub.test.js +497 -0
- package/test/server/Mail.account.test_.js +3 -3
- package/test/server/Mail.init.test_.js +10 -10
- package/test/server/Mail.test_.js +20 -20
- package/test/server/SSL.test_.js +54 -54
- package/test/server/Server.test.js +39 -39
- package/test/server/Service.test_.js +7 -7
- package/test/server/Subdomain.test.js +7 -7
- package/test/server/Web/Firewall.test.js +87 -87
- package/test/server/Web/Proxy.test.js +397 -0
- package/test/server/{Web.test_.js → Web.test.js} +137 -205
- package/test/server/__mocks__/fs.js +2 -2
- package/test/server/__mocks__/{globalCandy.js → globalOdac.js} +5 -5
- package/test/server/__mocks__/index.js +6 -6
- package/test/server/__mocks__/testFactories.js +1 -1
- package/test/server/__mocks__/testHelpers.js +7 -7
- package/.husky/pre-commit +0 -2
- package/.kiro/steering/code-style.md +0 -56
- package/.kiro/steering/product.md +0 -20
- package/.kiro/steering/structure.md +0 -77
- package/.kiro/steering/tech.md +0 -87
- package/AGENTS.md +0 -84
- package/bin/candy +0 -10
- package/bin/candypack +0 -10
- package/cli/index.js +0 -3
- package/cli/src/Cli.js +0 -348
- package/cli/src/Connector.js +0 -93
- package/cli/src/Monitor.js +0 -416
- package/core/Candy.js +0 -87
- package/core/Commands.js +0 -239
- package/core/Config.js +0 -1094
- package/core/Lang.js +0 -52
- package/core/Log.js +0 -43
- package/core/Process.js +0 -26
- package/docs/backend/05-controllers/02-your-trusty-candy-assistant.md +0 -20
- package/docs/server/01-installation/01-quick-install.md +0 -19
- package/docs/server/01-installation/02-manual-installation-via-npm.md +0 -9
- package/docs/server/02-get-started/01-core-concepts.md +0 -7
- package/docs/server/02-get-started/02-basic-commands.md +0 -57
- package/docs/server/02-get-started/03-cli-reference.md +0 -276
- package/docs/server/02-get-started/04-cli-quick-reference.md +0 -102
- package/docs/server/03-service/01-start-a-new-service.md +0 -57
- package/docs/server/03-service/02-delete-a-service.md +0 -48
- package/docs/server/04-web/01-create-a-website.md +0 -36
- package/docs/server/04-web/02-list-websites.md +0 -9
- package/docs/server/04-web/03-delete-a-website.md +0 -29
- package/docs/server/05-subdomain/01-create-a-subdomain.md +0 -32
- package/docs/server/05-subdomain/02-list-subdomains.md +0 -33
- package/docs/server/05-subdomain/03-delete-a-subdomain.md +0 -41
- package/docs/server/06-ssl/01-renew-an-ssl-certificate.md +0 -34
- package/docs/server/07-mail/01-create-a-mail-account.md +0 -23
- package/docs/server/07-mail/02-delete-a-mail-account.md +0 -20
- package/docs/server/07-mail/03-list-mail-accounts.md +0 -20
- package/docs/server/07-mail/04-change-account-password.md +0 -23
- package/framework/src/Candy.js +0 -81
- package/framework/src/Route.js +0 -455
- package/framework/src/Server.js +0 -15
- package/locale/de-DE.json +0 -80
- package/locale/en-US.json +0 -79
- package/locale/es-ES.json +0 -80
- package/locale/fr-FR.json +0 -80
- package/locale/pt-BR.json +0 -80
- package/locale/ru-RU.json +0 -80
- package/locale/tr-TR.json +0 -85
- package/locale/zh-CN.json +0 -80
- package/server/index.js +0 -5
- package/server/src/Api.js +0 -88
- package/server/src/DNS.js +0 -940
- package/server/src/Hub.js +0 -535
- package/server/src/Mail.js +0 -571
- package/server/src/SSL.js +0 -180
- package/server/src/Server.js +0 -27
- package/server/src/Service.js +0 -248
- package/server/src/Subdomain.js +0 -64
- package/server/src/Web/Firewall.js +0 -170
- package/server/src/Web/Proxy.js +0 -134
- package/server/src/Web.js +0 -451
- package/server/src/mail/imap.js +0 -1091
- package/server/src/mail/server.js +0 -32
- package/server/src/mail/smtp.js +0 -786
- package/test/server/Client.test.js +0 -338
- package/test/server/__mocks__/http-proxy.js +0 -105
- package/watchdog/index.js +0 -3
- package/watchdog/src/Watchdog.js +0 -156
- package/web/config.json +0 -5
- package/web/view/footer/main.html +0 -11
- /package/{framework/src → src}/Env.js +0 -0
- /package/{framework/src → src}/Route/Cron.js +0 -0
- /package/{framework/src → src}/Token.js +0 -0
|
@@ -53,7 +53,7 @@ class Validator {
|
|
|
53
53
|
result.result.message = message ?? ''
|
|
54
54
|
result.data = data ?? null
|
|
55
55
|
} else {
|
|
56
|
-
result.errors = this.#message['
|
|
56
|
+
result.errors = this.#message['_odac_form'] ? {_odac_form: this.#message['_odac_form']} : this.#message
|
|
57
57
|
}
|
|
58
58
|
return result
|
|
59
59
|
}
|
|
@@ -98,37 +98,37 @@ class Validator {
|
|
|
98
98
|
error = !value || (value !== 1 && value !== '1' && value !== 'on' && value !== 'yes' && value !== true)
|
|
99
99
|
break
|
|
100
100
|
case 'numeric':
|
|
101
|
-
error = value && value !== '' && !
|
|
101
|
+
error = value && value !== '' && !Odac.Var(value).is('numeric')
|
|
102
102
|
break
|
|
103
103
|
case 'alpha':
|
|
104
|
-
error = value && value !== '' && !
|
|
104
|
+
error = value && value !== '' && !Odac.Var(value).is('alpha')
|
|
105
105
|
break
|
|
106
106
|
case 'alphaspace':
|
|
107
|
-
error = value && value !== '' && !
|
|
107
|
+
error = value && value !== '' && !Odac.Var(value).is('alphaspace')
|
|
108
108
|
break
|
|
109
109
|
case 'alphanumeric':
|
|
110
|
-
error = value && value !== '' && !
|
|
110
|
+
error = value && value !== '' && !Odac.Var(value).is('alphanumeric')
|
|
111
111
|
break
|
|
112
112
|
case 'alphanumericspace':
|
|
113
|
-
error = value && value !== '' && !
|
|
113
|
+
error = value && value !== '' && !Odac.Var(value).is('alphanumericspace')
|
|
114
114
|
break
|
|
115
115
|
case 'email':
|
|
116
|
-
error = value && value !== '' && !
|
|
116
|
+
error = value && value !== '' && !Odac.Var(value).is('email')
|
|
117
117
|
break
|
|
118
118
|
case 'ip':
|
|
119
|
-
error = value && value !== '' && !
|
|
119
|
+
error = value && value !== '' && !Odac.Var(value).is('ip')
|
|
120
120
|
break
|
|
121
121
|
case 'float':
|
|
122
|
-
error = value && value !== '' && !
|
|
122
|
+
error = value && value !== '' && !Odac.Var(value).is('float')
|
|
123
123
|
break
|
|
124
124
|
case 'mac':
|
|
125
|
-
error = value && value !== '' && !
|
|
125
|
+
error = value && value !== '' && !Odac.Var(value).is('mac')
|
|
126
126
|
break
|
|
127
127
|
case 'domain':
|
|
128
|
-
error = value && value !== '' && !
|
|
128
|
+
error = value && value !== '' && !Odac.Var(value).is('domain')
|
|
129
129
|
break
|
|
130
130
|
case 'url':
|
|
131
|
-
error = value && value !== '' && !
|
|
131
|
+
error = value && value !== '' && !Odac.Var(value).is('url')
|
|
132
132
|
break
|
|
133
133
|
case 'username':
|
|
134
134
|
error = value && value !== '' && !/^[a-zA-Z0-9]+$/.test(value)
|
|
@@ -137,7 +137,7 @@ class Validator {
|
|
|
137
137
|
error = value && value !== '' && /<[^>]*>/g.test(value)
|
|
138
138
|
break
|
|
139
139
|
case 'usercheck':
|
|
140
|
-
error = !(await
|
|
140
|
+
error = !(await Odac.Auth.check())
|
|
141
141
|
break
|
|
142
142
|
case 'array':
|
|
143
143
|
error = value && !Array.isArray(value)
|
|
@@ -192,12 +192,12 @@ class Validator {
|
|
|
192
192
|
error = value && value !== '' && vars[1] && !new RegExp(vars[1]).test(value)
|
|
193
193
|
break
|
|
194
194
|
case 'user': {
|
|
195
|
-
if (!(await
|
|
195
|
+
if (!(await Odac.Auth.check())) {
|
|
196
196
|
error = true
|
|
197
197
|
} else {
|
|
198
|
-
const userData =
|
|
199
|
-
if (
|
|
200
|
-
error = !
|
|
198
|
+
const userData = Odac.Auth.user(vars[1])
|
|
199
|
+
if (Odac.Var(userData).is('bcrypt')) {
|
|
200
|
+
error = !Odac.Var(userData).hashCheck(value)
|
|
201
201
|
} else {
|
|
202
202
|
error = value !== userData
|
|
203
203
|
}
|
|
@@ -243,10 +243,10 @@ class Validator {
|
|
|
243
243
|
const ip = this.#request.ip()
|
|
244
244
|
const now = new Date().toISOString().slice(0, 13).replace(/[-:T]/g, '')
|
|
245
245
|
const page = this.#request.path()
|
|
246
|
-
const storage =
|
|
246
|
+
const storage = Odac.storage('sys')
|
|
247
247
|
const validation = storage.get('validation') || {}
|
|
248
248
|
|
|
249
|
-
this.#name = '
|
|
249
|
+
this.#name = '_odac_form'
|
|
250
250
|
|
|
251
251
|
if (Object.keys(this.#message).length > 0) {
|
|
252
252
|
if (!validation.brute) validation.brute = {}
|
|
@@ -257,8 +257,8 @@ class Validator {
|
|
|
257
257
|
validation.brute[now][page][ip]++
|
|
258
258
|
|
|
259
259
|
if (validation.brute[now][page][ip] >= maxAttempts) {
|
|
260
|
-
this.#message['
|
|
261
|
-
?
|
|
260
|
+
this.#message['_odac_form'] = Odac.Lang
|
|
261
|
+
? Odac.Lang.get('Too many failed attempts. Please try again later.')
|
|
262
262
|
: 'Too many failed attempts. Please try again later.'
|
|
263
263
|
}
|
|
264
264
|
}
|
|
@@ -44,7 +44,7 @@ class Var {
|
|
|
44
44
|
let hour = date.getHours()
|
|
45
45
|
let minute = date.getMinutes()
|
|
46
46
|
let second = date.getSeconds()
|
|
47
|
-
return
|
|
47
|
+
return Odac.Var(format).replace({
|
|
48
48
|
Y: year,
|
|
49
49
|
m: month < 10 ? `0${month}` : month,
|
|
50
50
|
d: day < 10 ? `0${day}` : day,
|
|
@@ -56,7 +56,7 @@ class Var {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
decrypt(key) {
|
|
59
|
-
if (!key) key =
|
|
59
|
+
if (!key) key = Odac.Config.encrypt.key
|
|
60
60
|
const iv = '2dea8a25e5e8f004'
|
|
61
61
|
try {
|
|
62
62
|
const encryptedText = Buffer.from(this.#value, 'base64')
|
|
@@ -71,7 +71,7 @@ class Var {
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
encrypt(key) {
|
|
74
|
-
if (!key) key =
|
|
74
|
+
if (!key) key = Odac.Config.encrypt.key
|
|
75
75
|
const iv = '2dea8a25e5e8f004'
|
|
76
76
|
const cipher = nodeCrypto.createCipheriv('aes-256-cbc', key, iv)
|
|
77
77
|
let encrypted = cipher.update(this.#value)
|
|
@@ -97,7 +97,7 @@ class Var {
|
|
|
97
97
|
let any = this.#any
|
|
98
98
|
this.#any = false
|
|
99
99
|
let result = !any
|
|
100
|
-
// if(\
|
|
100
|
+
// if(\Odac::config('locale')->get() == 'tr') $this->str = \Odac::var($this->str)->clear('Ç','ç','Ğ','ğ','İ','ı','Ö','ö','Ş','ş','Ü','ü');
|
|
101
101
|
if (args.includes('alpha')) result = (result || any) && ((any && result) || /^[A-Za-z]+$/.test(this.#value))
|
|
102
102
|
if (args.includes('alphaspace')) result = (result || any) && ((any && result) || /^[A-Za-z\s]+$/.test(this.#value))
|
|
103
103
|
if (args.includes('alphanumeric')) result = (result || any) && ((any && result) || /^[A-Za-z0-9]+$/.test(this.#value))
|
|
@@ -160,7 +160,7 @@ class Var {
|
|
|
160
160
|
if (args.length == 1) args = args[0]
|
|
161
161
|
if (['array', 'object'].includes(typeof this.#value)) {
|
|
162
162
|
let new_value = {}
|
|
163
|
-
for (const key of Object.keys(this.#value)) new_value[key] =
|
|
163
|
+
for (const key of Object.keys(this.#value)) new_value[key] = Odac.Var(this.#value[key]).replace(args)
|
|
164
164
|
return new_value
|
|
165
165
|
}
|
|
166
166
|
for (const arg of Object.keys(args)) this.#value = this.#value.replace(arg, args[arg])
|
|
@@ -3,15 +3,15 @@ const nodeCrypto = require('crypto')
|
|
|
3
3
|
class Form {
|
|
4
4
|
static FORM_TYPES = ['register', 'login', 'form']
|
|
5
5
|
|
|
6
|
-
static parse(content,
|
|
6
|
+
static parse(content, Odac) {
|
|
7
7
|
for (const type of this.FORM_TYPES) {
|
|
8
|
-
content = this.parseFormType(content,
|
|
8
|
+
content = this.parseFormType(content, Odac, type)
|
|
9
9
|
}
|
|
10
10
|
return content
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
static parseFormType(content,
|
|
14
|
-
const regex = new RegExp(`<
|
|
13
|
+
static parseFormType(content, Odac, type) {
|
|
14
|
+
const regex = new RegExp(`<odac:${type}[\\s\\S]*?<\\/odac:${type}>`, 'g')
|
|
15
15
|
const matches = content.match(regex)
|
|
16
16
|
if (!matches) return content
|
|
17
17
|
|
|
@@ -19,7 +19,7 @@ class Form {
|
|
|
19
19
|
const formToken = nodeCrypto.randomBytes(32).toString('hex')
|
|
20
20
|
const formConfig = this.extractConfig(match, formToken, type)
|
|
21
21
|
|
|
22
|
-
this.storeConfig(formToken, formConfig,
|
|
22
|
+
this.storeConfig(formToken, formConfig, Odac, type)
|
|
23
23
|
|
|
24
24
|
const generatedForm = this.generateForm(match, formConfig, formToken, type)
|
|
25
25
|
content = content.replace(match, generatedForm)
|
|
@@ -38,13 +38,13 @@ class Form {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
static storeConfig(token, config,
|
|
41
|
+
static storeConfig(token, config, Odac, type) {
|
|
42
42
|
if (type === 'register') {
|
|
43
|
-
this.storeRegisterConfig(token, config,
|
|
43
|
+
this.storeRegisterConfig(token, config, Odac)
|
|
44
44
|
} else if (type === 'login') {
|
|
45
|
-
this.storeLoginConfig(token, config,
|
|
45
|
+
this.storeLoginConfig(token, config, Odac)
|
|
46
46
|
} else if (type === 'form') {
|
|
47
|
-
this.storeFormConfig(token, config,
|
|
47
|
+
this.storeFormConfig(token, config, Odac)
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -69,7 +69,7 @@ class Form {
|
|
|
69
69
|
sets: []
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
const registerMatch = html.match(/<
|
|
72
|
+
const registerMatch = html.match(/<odac:register([^>]*)>/)
|
|
73
73
|
if (!registerMatch) return config
|
|
74
74
|
|
|
75
75
|
const registerTag = registerMatch[0]
|
|
@@ -79,7 +79,7 @@ class Form {
|
|
|
79
79
|
if (redirectMatch) config.redirect = redirectMatch[1]
|
|
80
80
|
if (autologinMatch) config.autologin = autologinMatch[1] !== 'false'
|
|
81
81
|
|
|
82
|
-
const submitMatch = html.match(/<
|
|
82
|
+
const submitMatch = html.match(/<odac:submit([^>/]*)(?:\/?>|>(.*?)<\/odac:submit>)/)
|
|
83
83
|
if (submitMatch) {
|
|
84
84
|
const submitTag = submitMatch[1]
|
|
85
85
|
const textMatch = submitTag.match(/text=["']([^"']+)["']/)
|
|
@@ -97,7 +97,7 @@ class Form {
|
|
|
97
97
|
if (idMatch) config.submitId = idMatch[1]
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
const fieldMatches = html.match(/<
|
|
100
|
+
const fieldMatches = html.match(/<odac:field[\s\S]*?<\/odac:field>/g)
|
|
101
101
|
if (fieldMatches) {
|
|
102
102
|
for (const fieldHtml of fieldMatches) {
|
|
103
103
|
const field = this.parseField(fieldHtml)
|
|
@@ -105,7 +105,7 @@ class Form {
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
const setMatches = html.match(/<
|
|
108
|
+
const setMatches = html.match(/<odac:set[^>]*\/?>/g)
|
|
109
109
|
if (setMatches) {
|
|
110
110
|
for (const setTag of setMatches) {
|
|
111
111
|
const set = this.parseSet(setTag)
|
|
@@ -117,7 +117,7 @@ class Form {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
static parseField(html) {
|
|
120
|
-
const fieldTagMatch = html.match(/<
|
|
120
|
+
const fieldTagMatch = html.match(/<odac:field([^>]*?)(?:\/>|>)/)
|
|
121
121
|
if (!fieldTagMatch) return null
|
|
122
122
|
|
|
123
123
|
const fieldTag = fieldTagMatch[0]
|
|
@@ -152,7 +152,7 @@ class Form {
|
|
|
152
152
|
if (uniqueMatch) field.unique = uniqueMatch[1] !== 'false'
|
|
153
153
|
if (skipMatch) field.skip = skipMatch[1] !== 'false'
|
|
154
154
|
|
|
155
|
-
const validateMatches = html.match(/<
|
|
155
|
+
const validateMatches = html.match(/<odac:validate[^>]*>/g)
|
|
156
156
|
if (validateMatches) {
|
|
157
157
|
for (const validateTag of validateMatches) {
|
|
158
158
|
const ruleMatch = validateTag.match(/rule=["']([^"']+)["']/)
|
|
@@ -195,36 +195,36 @@ class Form {
|
|
|
195
195
|
return set
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
static storeRegisterConfig(token, config,
|
|
199
|
-
if (!
|
|
200
|
-
if (!
|
|
198
|
+
static storeRegisterConfig(token, config, Odac) {
|
|
199
|
+
if (!Odac.View) Odac.View = {}
|
|
200
|
+
if (!Odac.View.registerForms) Odac.View.registerForms = {}
|
|
201
201
|
|
|
202
202
|
const formData = {
|
|
203
203
|
config: config,
|
|
204
204
|
created: Date.now(),
|
|
205
205
|
expires: Date.now() + 30 * 60 * 1000,
|
|
206
|
-
sessionId:
|
|
207
|
-
userAgent:
|
|
208
|
-
ip:
|
|
206
|
+
sessionId: Odac.Request.session('_client'),
|
|
207
|
+
userAgent: Odac.Request.header('user-agent'),
|
|
208
|
+
ip: Odac.Request.ip
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
|
|
212
|
-
|
|
211
|
+
Odac.View.registerForms[token] = formData
|
|
212
|
+
Odac.Request.session(`_register_form_${token}`, formData)
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
static generateRegisterForm(originalHtml, config, formToken) {
|
|
216
216
|
const submitText = config.submitText || 'Register'
|
|
217
217
|
const submitLoading = config.submitLoading || 'Processing...'
|
|
218
218
|
|
|
219
|
-
let innerContent = originalHtml.replace(/<
|
|
219
|
+
let innerContent = originalHtml.replace(/<odac:register[^>]*>/, '').replace(/<\/odac:register>/, '')
|
|
220
220
|
|
|
221
|
-
innerContent = innerContent.replace(/<
|
|
221
|
+
innerContent = innerContent.replace(/<odac:field[\s\S]*?<\/odac:field>/g, fieldMatch => {
|
|
222
222
|
const field = this.parseField(fieldMatch)
|
|
223
223
|
if (!field) return fieldMatch
|
|
224
224
|
return this.generateFieldHtml(field)
|
|
225
225
|
})
|
|
226
226
|
|
|
227
|
-
const submitMatch = innerContent.match(/<
|
|
227
|
+
const submitMatch = innerContent.match(/<odac:submit[\s\S]*?(?:<\/odac:submit>|\/?>)/)
|
|
228
228
|
if (submitMatch) {
|
|
229
229
|
let submitAttrs = `type="submit" data-submit-text="${submitText}" data-loading-text="${submitLoading}"`
|
|
230
230
|
if (config.submitClass) submitAttrs += ` class="${config.submitClass}"`
|
|
@@ -234,12 +234,12 @@ class Form {
|
|
|
234
234
|
innerContent = innerContent.replace(submitMatch[0], submitButton)
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
innerContent = innerContent.replace(/<
|
|
237
|
+
innerContent = innerContent.replace(/<odac:set[^>]*\/?>/g, '')
|
|
238
238
|
|
|
239
|
-
let html = `<form class="
|
|
240
|
-
html += ` <input type="hidden" name="
|
|
239
|
+
let html = `<form class="odac-register-form" data-odac-register="${formToken}" method="POST" action="/_odac/register" novalidate>\n`
|
|
240
|
+
html += ` <input type="hidden" name="_odac_register_token" value="${formToken}">\n`
|
|
241
241
|
html += innerContent
|
|
242
|
-
html += `\n <span class="
|
|
242
|
+
html += `\n <span class="odac-form-success" style="display:none;"></span>\n`
|
|
243
243
|
html += `</form>`
|
|
244
244
|
|
|
245
245
|
return html
|
|
@@ -249,12 +249,12 @@ class Form {
|
|
|
249
249
|
let html = ''
|
|
250
250
|
|
|
251
251
|
if (field.label && field.type !== 'checkbox') {
|
|
252
|
-
const fieldId = field.id || `
|
|
252
|
+
const fieldId = field.id || `odac-${field.name}`
|
|
253
253
|
html += `<label for="${fieldId}">${field.label}</label>\n`
|
|
254
254
|
}
|
|
255
255
|
|
|
256
256
|
const classAttr = field.class ? ` class="${field.class}"` : ''
|
|
257
|
-
const idAttr = field.id ? ` id="${field.id}"` : ` id="
|
|
257
|
+
const idAttr = field.id ? ` id="${field.id}"` : ` id="odac-${field.name}"`
|
|
258
258
|
|
|
259
259
|
if (field.type === 'checkbox') {
|
|
260
260
|
const attrs = this.buildHtml5Attributes(field)
|
|
@@ -375,7 +375,7 @@ class Form {
|
|
|
375
375
|
fields: []
|
|
376
376
|
}
|
|
377
377
|
|
|
378
|
-
const loginMatch = html.match(/<
|
|
378
|
+
const loginMatch = html.match(/<odac:login([^>]*)>/)
|
|
379
379
|
if (!loginMatch) return config
|
|
380
380
|
|
|
381
381
|
const loginTag = loginMatch[0]
|
|
@@ -383,7 +383,7 @@ class Form {
|
|
|
383
383
|
|
|
384
384
|
if (redirectMatch) config.redirect = redirectMatch[1]
|
|
385
385
|
|
|
386
|
-
const submitMatch = html.match(/<
|
|
386
|
+
const submitMatch = html.match(/<odac:submit([^>/]*)(?:\/?>|>(.*?)<\/odac:submit>)/)
|
|
387
387
|
if (submitMatch) {
|
|
388
388
|
const submitTag = submitMatch[1]
|
|
389
389
|
const textMatch = submitTag.match(/text=["']([^"']+)["']/)
|
|
@@ -401,7 +401,7 @@ class Form {
|
|
|
401
401
|
if (idMatch) config.submitId = idMatch[1]
|
|
402
402
|
}
|
|
403
403
|
|
|
404
|
-
const fieldMatches = html.match(/<
|
|
404
|
+
const fieldMatches = html.match(/<odac:field[\s\S]*?<\/odac:field>/g)
|
|
405
405
|
if (fieldMatches) {
|
|
406
406
|
for (const fieldHtml of fieldMatches) {
|
|
407
407
|
const field = this.parseField(fieldHtml)
|
|
@@ -412,36 +412,36 @@ class Form {
|
|
|
412
412
|
return config
|
|
413
413
|
}
|
|
414
414
|
|
|
415
|
-
static storeLoginConfig(token, config,
|
|
416
|
-
if (!
|
|
417
|
-
if (!
|
|
415
|
+
static storeLoginConfig(token, config, Odac) {
|
|
416
|
+
if (!Odac.View) Odac.View = {}
|
|
417
|
+
if (!Odac.View.loginForms) Odac.View.loginForms = {}
|
|
418
418
|
|
|
419
419
|
const formData = {
|
|
420
420
|
config: config,
|
|
421
421
|
created: Date.now(),
|
|
422
422
|
expires: Date.now() + 30 * 60 * 1000,
|
|
423
|
-
sessionId:
|
|
424
|
-
userAgent:
|
|
425
|
-
ip:
|
|
423
|
+
sessionId: Odac.Request.session('_client'),
|
|
424
|
+
userAgent: Odac.Request.header('user-agent'),
|
|
425
|
+
ip: Odac.Request.ip
|
|
426
426
|
}
|
|
427
427
|
|
|
428
|
-
|
|
429
|
-
|
|
428
|
+
Odac.View.loginForms[token] = formData
|
|
429
|
+
Odac.Request.session(`_login_form_${token}`, formData)
|
|
430
430
|
}
|
|
431
431
|
|
|
432
432
|
static generateLoginForm(originalHtml, config, formToken) {
|
|
433
433
|
const submitText = config.submitText || 'Login'
|
|
434
434
|
const submitLoading = config.submitLoading || 'Logging in...'
|
|
435
435
|
|
|
436
|
-
let innerContent = originalHtml.replace(/<
|
|
436
|
+
let innerContent = originalHtml.replace(/<odac:login[^>]*>/, '').replace(/<\/odac:login>/, '')
|
|
437
437
|
|
|
438
|
-
innerContent = innerContent.replace(/<
|
|
438
|
+
innerContent = innerContent.replace(/<odac:field[\s\S]*?<\/odac:field>/g, fieldMatch => {
|
|
439
439
|
const field = this.parseField(fieldMatch)
|
|
440
440
|
if (!field) return fieldMatch
|
|
441
441
|
return this.generateFieldHtml(field)
|
|
442
442
|
})
|
|
443
443
|
|
|
444
|
-
const submitMatch = innerContent.match(/<
|
|
444
|
+
const submitMatch = innerContent.match(/<odac:submit[\s\S]*?(?:<\/odac:submit>|\/?>)/)
|
|
445
445
|
if (submitMatch) {
|
|
446
446
|
let submitAttrs = `type="submit" data-submit-text="${submitText}" data-loading-text="${submitLoading}"`
|
|
447
447
|
if (config.submitClass) submitAttrs += ` class="${config.submitClass}"`
|
|
@@ -451,10 +451,10 @@ class Form {
|
|
|
451
451
|
innerContent = innerContent.replace(submitMatch[0], submitButton)
|
|
452
452
|
}
|
|
453
453
|
|
|
454
|
-
let html = `<form class="
|
|
455
|
-
html += ` <input type="hidden" name="
|
|
454
|
+
let html = `<form class="odac-login-form" data-odac-login="${formToken}" method="POST" action="/_odac/login" novalidate>\n`
|
|
455
|
+
html += ` <input type="hidden" name="_odac_login_token" value="${formToken}">\n`
|
|
456
456
|
html += innerContent
|
|
457
|
-
html += `\n <span class="
|
|
457
|
+
html += `\n <span class="odac-form-success" style="display:none;"></span>\n`
|
|
458
458
|
html += `</form>`
|
|
459
459
|
|
|
460
460
|
return html
|
|
@@ -476,7 +476,7 @@ class Form {
|
|
|
476
476
|
successMessage: null
|
|
477
477
|
}
|
|
478
478
|
|
|
479
|
-
const formMatch = html.match(/<
|
|
479
|
+
const formMatch = html.match(/<odac:form([^>]*)>/)
|
|
480
480
|
if (!formMatch) return config
|
|
481
481
|
|
|
482
482
|
const formTag = formMatch[0]
|
|
@@ -501,7 +501,7 @@ class Form {
|
|
|
501
501
|
if (redirectMatch) config.redirect = redirectMatch
|
|
502
502
|
if (successMatch) config.successMessage = successMatch
|
|
503
503
|
|
|
504
|
-
const submitMatch = html.match(/<
|
|
504
|
+
const submitMatch = html.match(/<odac:submit([^>/]*)(?:\/?>|>(.*?)<\/odac:submit>)/)
|
|
505
505
|
if (submitMatch) {
|
|
506
506
|
const submitTag = submitMatch[1]
|
|
507
507
|
const textMatch = submitTag.match(/text=["']([^"']+)["']/)
|
|
@@ -519,7 +519,7 @@ class Form {
|
|
|
519
519
|
if (idMatch) config.submitId = idMatch[1]
|
|
520
520
|
}
|
|
521
521
|
|
|
522
|
-
const fieldMatches = html.match(/<
|
|
522
|
+
const fieldMatches = html.match(/<odac:field[\s\S]*?<\/odac:field>/g)
|
|
523
523
|
if (fieldMatches) {
|
|
524
524
|
for (const fieldHtml of fieldMatches) {
|
|
525
525
|
const field = this.parseField(fieldHtml)
|
|
@@ -527,7 +527,7 @@ class Form {
|
|
|
527
527
|
}
|
|
528
528
|
}
|
|
529
529
|
|
|
530
|
-
const setMatches = html.match(/<
|
|
530
|
+
const setMatches = html.match(/<odac:set[^>]*\/?>/g)
|
|
531
531
|
if (setMatches) {
|
|
532
532
|
for (const setTag of setMatches) {
|
|
533
533
|
const set = this.parseSet(setTag)
|
|
@@ -538,32 +538,32 @@ class Form {
|
|
|
538
538
|
return config
|
|
539
539
|
}
|
|
540
540
|
|
|
541
|
-
static storeFormConfig(token, config,
|
|
542
|
-
if (!
|
|
543
|
-
if (!
|
|
541
|
+
static storeFormConfig(token, config, Odac) {
|
|
542
|
+
if (!Odac.View) Odac.View = {}
|
|
543
|
+
if (!Odac.View.customForms) Odac.View.customForms = {}
|
|
544
544
|
|
|
545
545
|
const formData = {
|
|
546
546
|
config: config,
|
|
547
547
|
created: Date.now(),
|
|
548
548
|
expires: Date.now() + 30 * 60 * 1000,
|
|
549
|
-
sessionId:
|
|
550
|
-
userAgent:
|
|
551
|
-
ip:
|
|
549
|
+
sessionId: Odac.Request.session('_client'),
|
|
550
|
+
userAgent: Odac.Request.header('user-agent'),
|
|
551
|
+
ip: Odac.Request.ip
|
|
552
552
|
}
|
|
553
553
|
|
|
554
|
-
|
|
555
|
-
|
|
554
|
+
Odac.View.customForms[token] = formData
|
|
555
|
+
Odac.Request.session(`_custom_form_${token}`, formData)
|
|
556
556
|
}
|
|
557
557
|
|
|
558
558
|
static generateCustomForm(originalHtml, config, formToken) {
|
|
559
559
|
const submitText = config.submitText || 'Submit'
|
|
560
560
|
const submitLoading = config.submitLoading || 'Processing...'
|
|
561
|
-
const action = config.action || '/
|
|
561
|
+
const action = config.action || '/_odac/form'
|
|
562
562
|
const method = config.method || 'POST'
|
|
563
563
|
|
|
564
|
-
let innerContent = originalHtml.replace(/<
|
|
564
|
+
let innerContent = originalHtml.replace(/<odac:form[^>]*>/, '').replace(/<\/odac:form>/, '')
|
|
565
565
|
|
|
566
|
-
innerContent = innerContent.replace(/<
|
|
566
|
+
innerContent = innerContent.replace(/<odac:field[\s\S]*?<\/odac:field>/g, fieldMatch => {
|
|
567
567
|
const field = this.parseField(fieldMatch)
|
|
568
568
|
if (!field) return fieldMatch
|
|
569
569
|
return this.generateFieldHtml(field)
|
|
@@ -572,7 +572,7 @@ class Form {
|
|
|
572
572
|
const escapeHtml = str =>
|
|
573
573
|
String(str).replace(/[&<>"']/g, m => ({'&': '&', '<': '<', '>': '>', '"': '"', "'": '''})[m])
|
|
574
574
|
|
|
575
|
-
const submitMatch = innerContent.match(/<
|
|
575
|
+
const submitMatch = innerContent.match(/<odac:submit[\s\S]*?(?:<\/odac:submit>|\/?>)/)
|
|
576
576
|
if (submitMatch) {
|
|
577
577
|
let submitAttrs = `type="submit" data-submit-text="${escapeHtml(submitText)}" data-loading-text="${escapeHtml(submitLoading)}"`
|
|
578
578
|
if (config.submitClass) submitAttrs += ` class="${escapeHtml(config.submitClass)}"`
|
|
@@ -582,15 +582,15 @@ class Form {
|
|
|
582
582
|
innerContent = innerContent.replace(submitMatch[0], submitButton)
|
|
583
583
|
}
|
|
584
584
|
|
|
585
|
-
innerContent = innerContent.replace(/<
|
|
585
|
+
innerContent = innerContent.replace(/<odac:set[^>]*\/?>/g, '')
|
|
586
586
|
|
|
587
|
-
let formAttrs = `class="
|
|
587
|
+
let formAttrs = `class="odac-custom-form${config.class ? ' ' + escapeHtml(config.class) : ''}" data-odac-form="${escapeHtml(formToken)}" method="${escapeHtml(method)}" action="${escapeHtml(action)}" novalidate`
|
|
588
588
|
if (config.id) formAttrs += ` id="${escapeHtml(config.id)}"`
|
|
589
589
|
|
|
590
590
|
let html = `<form ${formAttrs}>\n`
|
|
591
|
-
html += ` <input type="hidden" name="
|
|
591
|
+
html += ` <input type="hidden" name="_odac_form_token" value="${escapeHtml(formToken)}">\n`
|
|
592
592
|
html += innerContent
|
|
593
|
-
html += `\n <span class="
|
|
593
|
+
html += `\n <span class="odac-form-success" style="display:none;"></span>\n`
|
|
594
594
|
html += `</form>`
|
|
595
595
|
|
|
596
596
|
return html
|