@open-xchange/appsuite-codeceptjs 0.1.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 (48) hide show
  1. package/.env.defaults +47 -0
  2. package/README.md +40 -0
  3. package/chai.d.ts +5 -0
  4. package/customRerun.js +135 -0
  5. package/global.d.ts +5 -0
  6. package/index.js +187 -0
  7. package/package.json +39 -0
  8. package/src/actor.js +174 -0
  9. package/src/appsuiteHttpClient.js +155 -0
  10. package/src/chai.d.ts +6 -0
  11. package/src/chai.js +58 -0
  12. package/src/contexts/contexts.js +172 -0
  13. package/src/contexts/reseller.js +248 -0
  14. package/src/contexts.js +29 -0
  15. package/src/event.js +54 -0
  16. package/src/helper.js +817 -0
  17. package/src/pageobjects/calendar.js +226 -0
  18. package/src/pageobjects/contacts.js +148 -0
  19. package/src/pageobjects/drive.js +96 -0
  20. package/src/pageobjects/fragments/contact-autocomplete.js +45 -0
  21. package/src/pageobjects/fragments/contact-picker.js +50 -0
  22. package/src/pageobjects/fragments/dialogs.js +41 -0
  23. package/src/pageobjects/fragments/search.js +54 -0
  24. package/src/pageobjects/fragments/settings-mailfilter.js +90 -0
  25. package/src/pageobjects/fragments/settings.js +71 -0
  26. package/src/pageobjects/fragments/tinymce.js +41 -0
  27. package/src/pageobjects/fragments/topbar.js +43 -0
  28. package/src/pageobjects/fragments/viewer.js +67 -0
  29. package/src/pageobjects/mail.js +67 -0
  30. package/src/pageobjects/mobile/mobileCalendar.js +41 -0
  31. package/src/pageobjects/mobile/mobileContacts.js +40 -0
  32. package/src/pageobjects/mobile/mobileMail.js +51 -0
  33. package/src/pageobjects/tasks.js +58 -0
  34. package/src/plugins/emptyModule/index.js +21 -0
  35. package/src/plugins/settingsInit/index.js +35 -0
  36. package/src/plugins/testmetrics/index.js +135 -0
  37. package/src/soap/services/context.js +147 -0
  38. package/src/soap/services/oxaas.js +36 -0
  39. package/src/soap/services/resellerContext.js +65 -0
  40. package/src/soap/services/resellerUser.js +100 -0
  41. package/src/soap/services/user.js +114 -0
  42. package/src/soap/services/util.js +39 -0
  43. package/src/soap/soap.js +172 -0
  44. package/src/users/reseller.js +233 -0
  45. package/src/users/users.js +183 -0
  46. package/src/users.js +29 -0
  47. package/src/util.js +104 -0
  48. package/steps.d.ts +16 -0
@@ -0,0 +1,172 @@
1
+ /**
2
+ * @copyright Copyright (c) Open-Xchange GmbH, Germany <info@open-xchange.com>
3
+ * @license AGPL-3.0
4
+ *
5
+ * This code is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Affero General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU Affero General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License
16
+ * along with OX App Suite. If not, see <https://www.gnu.org/licenses/agpl-3.0.txt>.
17
+ *
18
+ * Any use of the work other than as authorized under this license or copyright law is prohibited.
19
+ */
20
+
21
+ const { performance, PerformanceObserver } = require('node:perf_hooks')
22
+ const SOAP = require('soap')
23
+ const dotenv = require('dotenv')
24
+
25
+ let AbortError
26
+ const pRetry = import('p-retry').then(module => {
27
+ AbortError = module.AbortError
28
+ return module.default
29
+ })
30
+
31
+ dotenv.config({ path: '.env' })
32
+ dotenv.config({ path: '.env.defaults' })
33
+
34
+ // This flag enables debug output including timing information.
35
+ const debug = process.env.DEBUG_SOAP === 'true'
36
+
37
+ // This URL is used to create the SOAP client.
38
+ const provisioningUrl = String(process.env.PROVISIONING_URL).replace(/\/$/, '')
39
+
40
+ // This user is used to authenticate against the provisioning API.
41
+ const provisioningAuth = {
42
+ auth: {
43
+ login: process.env.E2E_ADMIN_USER,
44
+ password: process.env.E2E_ADMIN_PW
45
+ }
46
+ }
47
+
48
+ /**
49
+ * This code creates a PerformanceObserver instance which asynchronously observes
50
+ * performance measurement events. It logs the name of the event (which is the name
51
+ * of the SOAP method in this context) and the time it took to execute in milliseconds.
52
+ *
53
+ * This is used for performance tracking of the SOAP methods.
54
+ * @see https://nodejs.org/api/perf_hooks.html
55
+ * @params {PerformanceObserverEntryList} items The list of performance entries.
56
+ * @returns {void}
57
+ */
58
+ const obs = new PerformanceObserver((items) => {
59
+ items.getEntries().forEach((entry) => {
60
+ if (debug) console.log(`${entry.name} took ${Math.round(entry.duration)}ms`)
61
+ })
62
+ })
63
+ obs.observe({ entryTypes: ['measure'] })
64
+
65
+ async function logSoapError (e) {
66
+ console.error(e?.originalError?.root?.Envelope?.Body?.Fault?.faultstring || e.message)
67
+ }
68
+
69
+ /**
70
+ * This function checks if the specified error should abort the retry.
71
+ * @param {Error} error The error to check.
72
+ * @returns {boolean} True if the error should abort the retry, false otherwise.
73
+ **/
74
+ function shouldAbortRetry (error) {
75
+ try {
76
+ const fault = error.root.Envelope.Body.Fault
77
+ const details = fault.detail
78
+ const blockedFaultStrings = [
79
+ /Context \d+ already exists/,
80
+ /Authentication failed/,
81
+ /Context \d+ does not exist/,
82
+ /CloudPluginException: username .* already exists/,
83
+ /CloudPluginException: context name must begin/,
84
+ /The displayname is already used/,
85
+ /already exists in this context/,
86
+ /Shared Domain already exists/,
87
+ /Shared Domain already in use/,
88
+ /No such user/
89
+ ]
90
+ const blockedExceptions = [
91
+ 'ContextExistsException',
92
+ 'InvalidCredentialsException',
93
+ 'NoSuchContextException'
94
+ ]
95
+ // return "details object contains any of the blocked items"
96
+ return blockedFaultStrings.some(msg => msg.test(fault.faultstring)) ||
97
+ blockedExceptions.some(exception => Object.hasOwnProperty.call(details, exception))
98
+ } catch (e) {
99
+ // some other error which is never blocked
100
+ return false
101
+ }
102
+ }
103
+
104
+ /**
105
+ * This function creates a SOAP client for the specified service type.
106
+ * @param {string} type The name of the service type.
107
+ * @returns {Promise<Object>} The SOAP client.
108
+ */
109
+ async function createClientAsync (type) {
110
+ const startMark = `${type}-start`
111
+ const endMark = `${type}-end`
112
+ performance.mark(startMark)
113
+ const endpoint = `${provisioningUrl}/webservices/${type}`
114
+ const url = `${endpoint}/?wsdl`
115
+ const client = await SOAP.createClientAsync(url, {
116
+ endpoint,
117
+ suppressStack: true,
118
+ wsdl_options: {
119
+ forever: true
120
+ },
121
+ gzip: true
122
+ })
123
+
124
+ // https://stackoverflow.com/questions/30740415/namespace-for-array-field-in-node-soap-client-node-js
125
+ client.wsdl.definitions.xmlns.ns1 = 'http://dataobjects.soap.admin.openexchange.com/xsd'
126
+ client.wsdl.xmlnsInEnvelope = client.wsdl._xmlnsMap()
127
+ performance.mark(endMark)
128
+ performance.measure(` ⏱ SOAP: ${type} -> createClientAsync`, startMark, endMark)
129
+
130
+ // This proxy effectively adds error handling, authentication and performance measurements to all methods of the SOAP client.
131
+ return new Proxy(client, {
132
+ get (target, prop, receiver) {
133
+ const origMethod = Reflect.get(target, prop, receiver)
134
+ if (typeof origMethod === 'function') {
135
+ return async function (options, clientOptions, ...args) {
136
+ const startMark = `${prop}-start`
137
+ const endMark = `${prop}-end`
138
+ performance.mark(startMark)
139
+ const soapOptions = { ...provisioningAuth, ...options }
140
+ if (soapOptions.auth) {
141
+ // only send login and password instead of complete admin object.
142
+ // this can fail because of ambiguous namespacing
143
+ soapOptions.auth = { login: soapOptions.auth.login, password: soapOptions.auth.password }
144
+ }
145
+
146
+ const result = await (await pRetry)(() => origMethod.apply(this, [soapOptions, { timeout: 10000, ...clientOptions }, ...args]), {
147
+ retries: 3,
148
+ onFailedAttempt: async error => {
149
+ if (shouldAbortRetry(error)) throw new (await AbortError)(error)
150
+ console.log(`Attempt ${error.attemptNumber} failed. There are ${error.retriesLeft} retries left.`)
151
+ }
152
+ }).catch(e => {
153
+ const soapError = e?.originalError?.root?.Envelope?.Body?.Fault
154
+ throw new Error(soapError?.faultstring || e.message)
155
+ })
156
+ performance.mark(endMark)
157
+ performance.measure(` ⏱ SOAP: ${type} -> ${prop}`, startMark, endMark)
158
+ // Return only the first result from the SOAP method call, as we don't need the SOAP envelope and other stuff.
159
+ if (!result || !result[0]) return
160
+ return result[0]?.return
161
+ }
162
+ } else {
163
+ return origMethod
164
+ }
165
+ }
166
+ })
167
+ }
168
+
169
+ module.exports = {
170
+ createClientAsync,
171
+ logSoapError
172
+ }
@@ -0,0 +1,233 @@
1
+ /**
2
+ * @copyright Copyright (c) Open-Xchange GmbH, Germany <info@open-xchange.com>
3
+ * @license AGPL-3.0
4
+ *
5
+ * This code is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Affero General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU Affero General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License
16
+ * along with OX App Suite. If not, see <https://www.gnu.org/licenses/agpl-3.0.txt>.
17
+ *
18
+ * Any use of the work other than as authorized under this license or copyright law is prohibited.
19
+ */
20
+
21
+ const event = require('../event')
22
+
23
+ const users = []
24
+ const usersToRemove = []
25
+ const preprovisionedUsers = []
26
+ const util = require('../util')
27
+ const short = require('short-uuid')
28
+ const resellerUserService = require('../soap/services/resellerUser')
29
+ const oxaasService = require('../soap/services/oxaas')
30
+
31
+ class User {
32
+ constructor (opt) {
33
+ this.userdata = opt.user
34
+ this.context = opt.context
35
+ this.session = {}
36
+ this.userAttributes = this.userdata.userAttributes || {}
37
+ return new Proxy(this, {
38
+ get (target, prop) {
39
+ return prop in target ? target[prop] : target.userdata[prop]
40
+ }
41
+ })
42
+ }
43
+
44
+ async remove () {
45
+ await resellerUserService.remove(
46
+ this.context.id,
47
+ this.get('id')
48
+ ).catch(async (err) => {
49
+ if (/No such user/.test(err.faultstring)) return // ignore
50
+ throw new util.PropagatedError(err)
51
+ })
52
+ users.splice(0, users.length, ...users.filter(u => u !== this))
53
+ event.emit(event.provisioning.user.removed, this)
54
+ }
55
+
56
+ async hasConfig (key, value) {
57
+ // Config structure is the following { userAttributes: { entries: [{ key: 'config', value: { entries: [{ key: 'key', value: value }] }}]} }
58
+ // Note that the soap lib will replace arrays with a single element by that element
59
+
60
+ // check if config exists and create config path if it does not exist
61
+ const userAttributes = this.userdata.userAttributes = this.userdata.userAttributes || {}
62
+ const entries = userAttributes.entries = userAttributes.entries ? [].concat(userAttributes.entries) : []
63
+ let configEntry = entries.find(entry => entry.key === 'config')
64
+ if (!configEntry) {
65
+ entries.push({ key: 'config', value: {} })
66
+ configEntry = entries[entries.length - 1]
67
+ }
68
+ const config = configEntry.value
69
+ const configEntries = config.entries = config.entries ? [].concat(config.entries) : []
70
+ let targetConfig = configEntries.find(entry => entry.key === key)
71
+ if (!targetConfig) {
72
+ configEntries.push({ key })
73
+ targetConfig = configEntries[configEntries.length - 1]
74
+ }
75
+ targetConfig.value = value
76
+
77
+ return resellerUserService.change(this.context, this.userdata)
78
+ }
79
+
80
+ hasAccessCombination (accessCombinationName) {
81
+ return resellerUserService.changeByModuleAccessName(this.context, this.get('id'), accessCombinationName)
82
+ }
83
+
84
+ getModuleAccess () {
85
+ return resellerUserService.getModuleAccess(this.context, this.get('id'))
86
+ }
87
+
88
+ async hasModuleAccess (moduleAccess) {
89
+ const currentAccess = await this.getModuleAccess()
90
+ return resellerUserService.changeByModuleAccess(this.context, this.get('id'), currentAccess, moduleAccess)
91
+ }
92
+
93
+ hasQuota (quota) {
94
+ return oxaasService.setMailQuota({
95
+ ctxid: this.context.id,
96
+ usrid: this.get('id'),
97
+ quota,
98
+ creds: util.admin()
99
+ }).catch((err) => { throw new util.PropagatedError(err) })
100
+ }
101
+
102
+ hasAlias (alias) {
103
+ // See if this alias has already been declared
104
+ if (this.userdata.aliases.includes(alias)) {
105
+ return
106
+ }
107
+ // If not, add it and save
108
+ this.userdata.aliases.push(alias)
109
+ const userdata = { id: this.get('id'), aliases: this.userdata.aliases }
110
+ return resellerUserService.change(this.context, userdata)
111
+ }
112
+
113
+ hasCapability (capability) {
114
+ this._setCapability(capability, true)
115
+ }
116
+
117
+ _setCapability (cap, value) {
118
+ const userAttributes = this.userAttributes
119
+ const configMap = userAttributes.entries.find(entry => entry.key === 'config') || { key: 'config' }
120
+ configMap.value = configMap.value || { entries: [] }
121
+ configMap.value.entries.push({ key: `com.openexchange.capability.${cap}`, value })
122
+
123
+ return resellerUserService.change(this.context, { id: this.get('id'), userAttributes })
124
+ }
125
+
126
+ doesntHaveCapability (capability) {
127
+ this._setCapability(capability, false)
128
+ }
129
+
130
+ get (key) {
131
+ return this.userdata[key]
132
+ }
133
+
134
+ // eslint-disable-next-line camelcase
135
+ static getRandom ({ name = 'test.user', password = util.getDefaultUserPassword(), sur_name = '', given_name = 'User' } = {}) {
136
+ const id = short.generate().slice(0, 9).toLowerCase()
137
+ // eslint-disable-next-line camelcase
138
+ if (!sur_name) sur_name = id
139
+ return {
140
+ name: `${name}-${id}`,
141
+ password,
142
+ // eslint-disable-next-line camelcase
143
+ sur_name,
144
+ // eslint-disable-next-line camelcase
145
+ given_name
146
+ }
147
+ }
148
+
149
+ get login () {
150
+ const { name, password } = this.userdata
151
+ return { name, password }
152
+ }
153
+
154
+ static async create (user = User.getRandom(), ctx = {}, preprovisioned = false) {
155
+ if (preprovisionedUsers.length > 0 && !preprovisioned) {
156
+ let index = 0
157
+ if (ctx.id) index = preprovisionedUsers.findIndex(u => u.context.id === ctx.id)
158
+ if (index !== -1) {
159
+ const currentUser = preprovisionedUsers[index]
160
+ preprovisionedUsers.splice(index, 1)
161
+ usersToRemove.push(currentUser)
162
+ users.push(currentUser)
163
+ return currentUser
164
+ }
165
+ }
166
+
167
+ if (!ctx.id || !ctx.name) {
168
+ const contexts = require('../contexts/reseller')()
169
+ // @ts-ignore
170
+ ctx = contexts[0] || await contexts.create()
171
+ }
172
+ const usrdata = {
173
+ ...{
174
+ primaryEmail: `${user.name}@${util.mxDomain()}`,
175
+ display_name: user.name,
176
+ sur_name: user.sur_name,
177
+ given_name: user.given_name,
178
+ name: user.name,
179
+ email1: `${user.name}@${util.mxDomain()}`,
180
+ password: user.password,
181
+ imapLogin: user.name,
182
+ imapServer: user.imapServer || util.imapServer(),
183
+ smtpServer: user.smtpServer || util.smtpServer()
184
+ },
185
+ ...user
186
+ }
187
+ event.emit(event.provisioning.user.create, usrdata, ctx)
188
+
189
+ let data
190
+ try {
191
+ data = await resellerUserService.createByModuleAccessName(ctx, usrdata)
192
+ } catch (error) {
193
+ if (!/FLD-0038/.test(error.faultstring)) {
194
+ throw new util.PropagatedError(error)
195
+ }
196
+ return new Promise(function (resolve, reject) {
197
+ setTimeout(function () {
198
+ User.create(user, ctx).then(resolve, reject)
199
+ }, 1000)
200
+ })
201
+ }
202
+ const newUser = new User({ user: data, context: ctx })
203
+ if (!preprovisioned) users.push(newUser)
204
+ if (preprovisioned) preprovisionedUsers.push(newUser)
205
+ event.emit(event.provisioning.user.created, newUser)
206
+ return newUser
207
+ }
208
+
209
+ change (userdata) {
210
+ return resellerUserService.change(this.context, userdata)
211
+ }
212
+
213
+ static async removeAll () {
214
+ // Make sure to also remove the preprovisioned users
215
+ users.splice(0, 0, ...usersToRemove.splice(0, usersToRemove.length))
216
+ let user = users.pop()
217
+ while (user) {
218
+ await user.remove()
219
+ user = users.pop()
220
+ }
221
+ return users
222
+ }
223
+ }
224
+
225
+ module.exports = () => {
226
+ return new Proxy(users, {
227
+ // act like an array if an index is being used
228
+ get (target, prop) {
229
+ if (prop in target) { return target[prop] }
230
+ return User[prop]
231
+ }
232
+ })
233
+ }
@@ -0,0 +1,183 @@
1
+ /**
2
+ * @copyright Copyright (c) Open-Xchange GmbH, Germany <info@open-xchange.com>
3
+ * @license AGPL-3.0
4
+ *
5
+ * This code is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Affero General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU Affero General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License
16
+ * along with OX App Suite. If not, see <https://www.gnu.org/licenses/agpl-3.0.txt>.
17
+ *
18
+ * Any use of the work other than as authorized under this license or copyright law is prohibited.
19
+ */
20
+
21
+ /* eslint-disable camelcase */
22
+ const event = require('../event')
23
+
24
+ const users = []
25
+ const util = require('../util')
26
+ const short = require('short-uuid')
27
+ const userService = require('../soap/services/user')
28
+
29
+ class User {
30
+ constructor (opt) {
31
+ this.userdata = opt.user
32
+ this.context = opt.context
33
+ return new Proxy(this, {
34
+ get (target, prop) {
35
+ return prop in target ? target[prop] : target.userdata[prop]
36
+ }
37
+ })
38
+ }
39
+
40
+ async remove () {
41
+ await userService.remove(this.context, this.get('id'))
42
+ users.splice(0, users.length, ...users.filter(u => u !== this))
43
+ event.emit(event.provisioning.user.removed, this)
44
+ }
45
+
46
+ async hasConfig (key, value) {
47
+ // Config structure is the following { userAttributes: { entries: [{ key: 'config', value: { entries: [{ key: 'key', value: value }] }}]} }
48
+ // Note that the soap lib will replace arrays with a single element by that element
49
+
50
+ // check if config exists and create config path if it does not exist
51
+ const userAttributes = this.userdata.userAttributes = this.userdata.userAttributes || {}
52
+ const entries = userAttributes.entries = userAttributes.entries ? [].concat(userAttributes.entries) : []
53
+ let configEntry = entries.find(entry => entry.key === 'config')
54
+ if (!configEntry) {
55
+ entries.push({ key: 'config', value: {} })
56
+ configEntry = entries[entries.length - 1]
57
+ }
58
+ const config = configEntry.value
59
+ const configEntries = config.entries = config.entries ? [].concat(config.entries) : []
60
+ let targetConfig = configEntries.find(entry => entry.key === key)
61
+ if (!targetConfig) {
62
+ configEntries.push({ key })
63
+ targetConfig = configEntries[configEntries.length - 1]
64
+ }
65
+ targetConfig.value = value
66
+
67
+ return userService.change(this.context, this.userdata)
68
+ }
69
+
70
+ hasAlias (alias) {
71
+ // See if this alias has already been declared
72
+ if (this.userdata.aliases.includes(alias)) return
73
+ // If not, add it and save
74
+ this.userdata.aliases.push(alias)
75
+ return userService.change(this.context, this.userdata)
76
+ }
77
+
78
+ doesntHaveAlias (alias) {
79
+ const index = this.userdata.aliases.indexOf(alias)
80
+ // See if this alias has already been declared
81
+ if (index < 0) return
82
+ this.userdata.aliases.splice(index)
83
+ return userService.change(this.context, this.userdata)
84
+ }
85
+
86
+ hasAccessCombination (accessCombinationName) {
87
+ return userService.changeByModuleAccessName(this.context, this.get('id'), accessCombinationName)
88
+ }
89
+
90
+ getModuleAccess () {
91
+ return userService.getModuleAccess(this.context, this.get('id'))
92
+ }
93
+
94
+ async hasModuleAccess (moduleAccess) {
95
+ const currentAccess = await this.getModuleAccess()
96
+ return userService.changeByModuleAccess(this.context, this.get('id'), currentAccess, moduleAccess)
97
+ }
98
+
99
+ hasCapability (capsToAdd) {
100
+ return userService.changeCapabilities(this.context, this.get('id'), capsToAdd)
101
+ }
102
+
103
+ doesntHaveCapability (capsToRemove) {
104
+ return userService.changeCapabilities(this.context, this.get('id'), undefined, capsToRemove)
105
+ }
106
+
107
+ get login () {
108
+ return `${this.get('name')}@${this.context.id}`
109
+ }
110
+
111
+ get (key) {
112
+ return this.userdata[key]
113
+ }
114
+
115
+ toJSON () {
116
+ return {
117
+ context: { ...this.context },
118
+ ...this.userdata
119
+ }
120
+ }
121
+
122
+ static getRandom ({ name = 'test.user', password = util.getDefaultUserPassword(), sur_name = '', given_name = 'User' } = {}) {
123
+ const id = short.generate().slice(0, 9).toLowerCase()
124
+ // eslint-disable-next-line camelcase
125
+ if (!sur_name) sur_name = id
126
+ if (name === 'test.user') name = `${name}-${id}`
127
+ const domain = util.mxDomain()
128
+ return {
129
+ name,
130
+ primaryEmail: `${name}@${domain}`,
131
+ email1: `${name}@${domain}`,
132
+ password,
133
+ sur_name,
134
+ given_name
135
+ }
136
+ }
137
+
138
+ static async create (user = this.getRandom(), ctx = {}) {
139
+ const usrdata = Object.assign({
140
+ display_name: user.name,
141
+ imapLogin: user.name,
142
+ imapServer: util.imapServer(),
143
+ smtpServer: util.smtpServer()
144
+ }, user)
145
+ event.emit(event.provisioning.user.create, usrdata, ctx)
146
+ const contexts = require('../contexts/contexts')()
147
+ let userContext
148
+ try {
149
+ // @ts-ignore
150
+ userContext = await contexts.reuse(ctx, ctx.admin, ctx.auth)
151
+ } catch (e) {
152
+ // @ts-ignore
153
+ userContext = await contexts.create(Object.assign({ maxQuota: 1000 }, ctx))
154
+ }
155
+ const data = await userService.create(userContext, usrdata)
156
+ const index = users.push(new User({ user: data, context: userContext })) - 1
157
+ event.emit(event.provisioning.user.created, users[index])
158
+ return users[index]
159
+ }
160
+
161
+ change (userdata) {
162
+ return userService.change(this.context, userdata)
163
+ }
164
+
165
+ static async removeAll () {
166
+ let user = users.pop()
167
+ while (user) {
168
+ await user.remove()
169
+ user = users.pop()
170
+ }
171
+ return users
172
+ }
173
+ }
174
+
175
+ module.exports = () => {
176
+ return new Proxy(users, {
177
+ // act like an array if an index is being used
178
+ get (target, prop) {
179
+ if (prop in target) { return target[prop] }
180
+ return User[prop]
181
+ }
182
+ })
183
+ }
package/src/users.js ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @copyright Copyright (c) Open-Xchange GmbH, Germany <info@open-xchange.com>
3
+ * @license AGPL-3.0
4
+ *
5
+ * This code is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Affero General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or
8
+ * (at your option) any later version.
9
+ *
10
+ * This program is distributed in the hope that it will be useful,
11
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ * GNU Affero General Public License for more details.
14
+ *
15
+ * You should have received a copy of the GNU Affero General Public License
16
+ * along with OX App Suite. If not, see <https://www.gnu.org/licenses/agpl-3.0.txt>.
17
+ *
18
+ * Any use of the work other than as authorized under this license or copyright law is prohibited.
19
+ */
20
+
21
+ let moduleToLoad
22
+
23
+ if (process.env.PROVISIONING_API === 'reseller') {
24
+ moduleToLoad = './users/reseller'
25
+ } else {
26
+ moduleToLoad = './users/users'
27
+ }
28
+
29
+ module.exports = require(moduleToLoad)