]>
Commit | Line | Data |
---|---|---|
658bfdff WB |
1 | Ext.define('Proxmox.window.ACMEPluginEdit', { |
2 | extend: 'Proxmox.window.Edit', | |
3 | xtype: 'pmxACMEPluginEdit', | |
4 | mixins: ['Proxmox.Mixin.CBind'], | |
5 | ||
6 | //onlineHelp: 'sysadmin_certs_acme_plugins', | |
7 | ||
8 | isAdd: true, | |
9 | isCreate: false, | |
10 | ||
11 | width: 550, | |
12 | ||
13 | acmeUrl: undefined, | |
14 | ||
15 | subject: 'ACME DNS Plugin', | |
16 | ||
17 | cbindData: function(config) { | |
18 | let me = this; | |
19 | return { | |
20 | challengeSchemaUrl: `/api2/json/${me.acmeUrl}/challenge-schema`, | |
21 | }; | |
22 | }, | |
23 | ||
24 | items: [ | |
25 | { | |
26 | xtype: 'inputpanel', | |
27 | // we dynamically create fields from the given schema | |
28 | // things we have to do here: | |
29 | // * save which fields we created to remove them again | |
30 | // * split the data from the generic 'data' field into the boxes | |
31 | // * on deletion collect those values again | |
32 | // * save the original values of the data field | |
33 | createdFields: {}, | |
34 | createdInitially: false, | |
35 | originalValues: {}, | |
36 | createSchemaFields: function(schema) { | |
37 | let me = this; | |
38 | // we know where to add because we define it right below | |
39 | let container = me.down('container'); | |
40 | let datafield = me.down('field[name=data]'); | |
41 | let hintfield = me.down('field[name=hint]'); | |
42 | if (!me.createdInitially) { | |
43 | [me.originalValues] = Proxmox.Utils.parseACMEPluginData(datafield.getValue()); | |
44 | } | |
45 | ||
46 | // collect values from custom fields and add it to 'data'', | |
47 | // then remove the custom fields | |
48 | let data = []; | |
49 | for (const [name, field] of Object.entries(me.createdFields)) { | |
50 | let value = field.getValue(); | |
51 | if (value !== undefined && value !== null && value !== '') { | |
52 | data.push(`${name}=${value}`); | |
53 | } | |
54 | container.remove(field); | |
55 | } | |
56 | let datavalue = datafield.getValue(); | |
57 | if (datavalue !== undefined && datavalue !== null && datavalue !== '') { | |
58 | data.push(datavalue); | |
59 | } | |
60 | datafield.setValue(data.join('\n')); | |
61 | ||
62 | me.createdFields = {}; | |
63 | ||
64 | if (typeof schema.fields !== 'object') { | |
65 | schema.fields = {}; | |
66 | } | |
67 | // create custom fields according to schema | |
68 | let gotSchemaField = false; | |
69 | for (const [name, definition] of Object | |
70 | .entries(schema.fields) | |
71 | .sort((a, b) => a[0].localeCompare(b[0])) | |
72 | ) { | |
73 | let xtype; | |
74 | switch (definition.type) { | |
75 | case 'string': | |
76 | xtype = 'proxmoxtextfield'; | |
77 | break; | |
78 | case 'integer': | |
79 | xtype = 'proxmoxintegerfield'; | |
80 | break; | |
81 | case 'number': | |
82 | xtype = 'numberfield'; | |
83 | break; | |
84 | default: | |
85 | console.warn(`unknown type '${definition.type}'`); | |
86 | xtype = 'proxmoxtextfield'; | |
87 | break; | |
88 | } | |
89 | ||
90 | let label = name; | |
91 | if (typeof definition.name === "string") { | |
92 | label = definition.name; | |
93 | } | |
94 | ||
95 | let field = Ext.create({ | |
96 | xtype, | |
97 | name: `custom_${name}`, | |
98 | fieldLabel: label, | |
99 | width: '100%', | |
100 | labelWidth: 150, | |
101 | labelSeparator: '=', | |
102 | emptyText: definition.default || '', | |
103 | autoEl: definition.description ? { | |
104 | tag: 'div', | |
105 | 'data-qtip': definition.description, | |
106 | } : undefined, | |
107 | }); | |
108 | ||
109 | me.createdFields[name] = field; | |
110 | container.add(field); | |
111 | gotSchemaField = true; | |
112 | } | |
113 | datafield.setHidden(gotSchemaField); // prefer schema-fields | |
114 | ||
115 | if (schema.description) { | |
116 | hintfield.setValue(schema.description); | |
117 | hintfield.setHidden(false); | |
118 | } else { | |
119 | hintfield.setValue(''); | |
120 | hintfield.setHidden(true); | |
121 | } | |
122 | ||
123 | // parse data from field and set it to the custom ones | |
124 | let extradata = []; | |
125 | [data, extradata] = Proxmox.Utils.parseACMEPluginData(datafield.getValue()); | |
126 | for (const [key, value] of Object.entries(data)) { | |
127 | if (me.createdFields[key]) { | |
128 | me.createdFields[key].setValue(value); | |
129 | me.createdFields[key].originalValue = me.originalValues[key]; | |
130 | } else { | |
131 | extradata.push(`${key}=${value}`); | |
132 | } | |
133 | } | |
134 | datafield.setValue(extradata.join('\n')); | |
135 | if (!me.createdInitially) { | |
136 | datafield.resetOriginalValue(); | |
137 | me.createdInitially = true; // save that we initally set that | |
138 | } | |
139 | }, | |
140 | ||
141 | onGetValues: function(values) { | |
142 | let me = this; | |
143 | let win = me.up('pmxACMEPluginEdit'); | |
144 | if (win.isCreate) { | |
145 | values.id = values.plugin; | |
146 | values.type = 'dns'; // the only one for now | |
147 | } | |
148 | delete values.plugin; | |
149 | ||
150 | Proxmox.Utils.delete_if_default(values, 'validation-delay', '30', win.isCreate); | |
151 | ||
152 | let data = ''; | |
153 | for (const [name, field] of Object.entries(me.createdFields)) { | |
154 | let value = field.getValue(); | |
155 | if (value !== null && value !== undefined && value !== '') { | |
156 | data += `${name}=${value}\n`; | |
157 | } | |
158 | delete values[`custom_${name}`]; | |
159 | } | |
160 | values.data = Ext.util.Base64.encode(data + values.data); | |
161 | return values; | |
162 | }, | |
163 | ||
164 | items: [ | |
165 | { | |
166 | xtype: 'pmxDisplayEditField', | |
167 | cbind: { | |
168 | editable: (get) => get('isCreate'), | |
169 | submitValue: (get) => get('isCreate'), | |
170 | }, | |
171 | editConfig: { | |
172 | flex: 1, | |
173 | xtype: 'proxmoxtextfield', | |
174 | allowBlank: false, | |
175 | }, | |
176 | name: 'plugin', | |
177 | labelWidth: 150, | |
178 | fieldLabel: gettext('Plugin ID'), | |
179 | }, | |
180 | { | |
181 | xtype: 'proxmoxintegerfield', | |
182 | name: 'validation-delay', | |
183 | labelWidth: 150, | |
184 | fieldLabel: gettext('Validation Delay'), | |
185 | emptyText: 30, | |
186 | cbind: { | |
187 | deleteEmpty: '{!isCreate}', | |
188 | }, | |
189 | minValue: 0, | |
190 | maxValue: 48*60*60, | |
191 | }, | |
192 | { | |
193 | xtype: 'pmxACMEApiSelector', | |
194 | name: 'api', | |
195 | labelWidth: 150, | |
196 | cbind: { | |
197 | url: '{challengeSchemaUrl}', | |
198 | }, | |
199 | listeners: { | |
200 | change: function(selector) { | |
201 | let schema = selector.getSchema(); | |
202 | selector.up('inputpanel').createSchemaFields(schema); | |
203 | }, | |
204 | }, | |
205 | }, | |
206 | { | |
207 | xtype: 'textarea', | |
208 | fieldLabel: gettext('API Data'), | |
209 | labelWidth: 150, | |
210 | name: 'data', | |
211 | }, | |
212 | { | |
213 | xtype: 'displayfield', | |
214 | fieldLabel: gettext('Hint'), | |
215 | labelWidth: 150, | |
216 | name: 'hint', | |
217 | hidden: true, | |
218 | }, | |
219 | ], | |
220 | }, | |
221 | ], | |
222 | ||
223 | initComponent: function() { | |
224 | var me = this; | |
225 | ||
226 | if (!me.acmeUrl) { | |
227 | throw "no acmeUrl given"; | |
228 | } | |
229 | ||
230 | me.callParent(); | |
231 | ||
232 | if (!me.isCreate) { | |
233 | me.load({ | |
234 | success: function(response, opts) { | |
235 | me.setValues(response.result.data); | |
236 | }, | |
237 | }); | |
238 | } else { | |
239 | me.method = 'POST'; | |
240 | } | |
241 | }, | |
242 | }); |