expressa 1.0.5 → 1.1.3

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 (46) hide show
  1. package/.circleci/config.yml +1 -1
  2. package/auth/index.js +5 -1
  3. package/auth/jwt.js +9 -13
  4. package/controllers/install.js +1 -1
  5. package/controllers/status.js +2 -1
  6. package/controllers/users.js +3 -3
  7. package/index.js +2 -2
  8. package/listeners_users.js +1 -2
  9. package/listeners_validation.js +4 -0
  10. package/middleware/{users_permissions.js → permissions.js} +4 -4
  11. package/modules/admin/dist/index.html +1 -1
  12. package/modules/admin/dist/static/css/chunk-1059.220d4af5.css +1 -0
  13. package/modules/admin/dist/static/css/{chunk-f116.2ff74e8a.css → chunk-418a.5ee55031.css} +1 -1
  14. package/modules/admin/dist/static/css/chunk-787e.1d849865.css +1 -0
  15. package/modules/admin/dist/static/css/chunk-d0cd.97323951.css +1 -0
  16. package/modules/admin/dist/static/css/{chunk-759b.3a895a1e.css → chunk-f075.3a895a1e.css} +0 -0
  17. package/modules/admin/dist/static/css/chunk-libs.327ad89e.css +14 -0
  18. package/modules/admin/dist/static/js/{app.5f6e0e4c.js → app.4c984719.js} +1 -1
  19. package/modules/admin/dist/static/js/chunk-1059.e6aa7b61.js +1 -0
  20. package/modules/admin/dist/static/js/chunk-418a.e0987b3c.js +1 -0
  21. package/modules/admin/dist/static/js/chunk-787e.3ee96fce.js +1 -0
  22. package/modules/admin/dist/static/js/chunk-8bab.7052832d.js +2 -0
  23. package/modules/admin/dist/static/js/{chunk-23bd.5fa24c85.js.LICENSE.txt → chunk-8bab.7052832d.js.LICENSE.txt} +1 -1
  24. package/modules/admin/dist/static/js/chunk-d0cd.1781b9dd.js +1 -0
  25. package/modules/admin/dist/static/js/chunk-f075.315ceec1.js +1 -0
  26. package/modules/admin/dist/static/js/chunk-libs.06c38828.js +2 -0
  27. package/modules/admin/dist/static/js/{chunk-libs.b6f27cfe.js.LICENSE.txt → chunk-libs.06c38828.js.LICENSE.txt} +1 -1
  28. package/modules/admin/package.json +3 -3
  29. package/modules/admin/src/components/JSONEditor.vue +181 -167
  30. package/modules/admin/src/main.js +2 -2
  31. package/modules/admin/src/router/index.js +185 -185
  32. package/modules/admin/src/views/ListDocuments2.vue +29 -7
  33. package/modules/permissions/permissions.js +9 -3
  34. package/package.json +1 -1
  35. package/util.js +2 -2
  36. package/modules/admin/dist/static/css/chunk-0884.40d0b632.css +0 -1
  37. package/modules/admin/dist/static/css/chunk-34ab.f9393b1e.css +0 -1
  38. package/modules/admin/dist/static/css/chunk-fb07.ac81d7d6.css +0 -1
  39. package/modules/admin/dist/static/css/chunk-libs.68e8d170.css +0 -14
  40. package/modules/admin/dist/static/js/chunk-0884.5ca2b4c5.js +0 -1
  41. package/modules/admin/dist/static/js/chunk-23bd.5fa24c85.js +0 -2
  42. package/modules/admin/dist/static/js/chunk-34ab.06400cb6.js +0 -1
  43. package/modules/admin/dist/static/js/chunk-759b.89a889b6.js +0 -1
  44. package/modules/admin/dist/static/js/chunk-f116.b616ebb3.js +0 -1
  45. package/modules/admin/dist/static/js/chunk-fb07.075ac852.js +0 -1
  46. package/modules/admin/dist/static/js/chunk-libs.b6f27cfe.js +0 -2
@@ -1,185 +1,185 @@
1
- import Vue from 'vue'
2
- import Router from 'vue-router'
3
-
4
- // in development-env not use lazy-loading, because lazy-loading too many pages will cause webpack hot update too slow. so only in production use lazy-loading;
5
- // detail: https://panjiachen.github.io/vue-element-admin-site/#/lazy-loading
6
-
7
- Vue.use(Router)
8
-
9
- /* Layout */
10
- import Layout from '../views/layout/Layout'
11
-
12
- const capitalize = (s) => {
13
- if (typeof s !== 'string') return ''
14
- return s.charAt(0).toUpperCase() + s.slice(1)
15
- }
16
-
17
- /**
18
- * hidden: true if `hidden:true` will not show in the sidebar(default is false)
19
- * alwaysShow: true if set true, will always show the root menu, whatever its child routes length
20
- * if not set alwaysShow, only more than one route under the children
21
- * it will becomes nested mode, otherwise not show the root menu
22
- * redirect: noredirect if `redirect:noredirect` will no redirect in the breadcrumb
23
- * name:'router-name' the name is used by <keep-alive> (must set!!!)
24
- * meta : {
25
- title: 'title' the name show in submenu and breadcrumb (recommend set)
26
- icon: 'svg-name' the icon show in the sidebar,
27
- }
28
- **/
29
-
30
- export const constantRouterMap = [
31
- { path: '/login', component: () => import('@/views/login/index'), hidden: true },
32
- { path: '/install', component: () => import('@/views/Install'), hidden: true },
33
- { path: '/404', component: () => import('@/views/404'), hidden: true },
34
-
35
- {
36
- path: '/',
37
- component: Layout,
38
- redirect: '/home',
39
- name: 'Home',
40
- meta: { title: 'Home', icon: 'home-alt' },
41
- children: [{
42
- path: 'home',
43
- meta: { title: 'Home', icon: 'home-alt' },
44
- component: () => import('@/views/Home')
45
- }, {
46
- path: '/edit/:collectionName/:id',
47
- component: () => import('@/views/EditDocument'),
48
- hidden: true
49
- }]
50
- },
51
-
52
- {
53
- path: '/users',
54
- redirect: '/users/list',
55
- component: Layout,
56
- name: 'Users',
57
- meta: { title: 'People', icon: 'users-alt' },
58
- children: [{
59
- path: 'list',
60
- meta: { title: 'Users', icon: 'users-alt' },
61
- name: 'users2',
62
- component: () => import('@/views/ListDocuments2'),
63
- props: { collectionName: 'users' },
64
- }, {
65
- path: 'add',
66
- meta: { title: 'Add User', icon: 'plus' },
67
- name: 'newuser',
68
- component: () => import('@/views/EditDocument'),
69
- props: { collectionName: 'users', id: 'create' },
70
- }, {
71
- path: 'role',
72
- meta: { title: 'Roles', icon: 'shield-check' },
73
- name: 'role',
74
- component: () => import('@/views/ListDocuments2'),
75
- props: { collectionName: 'role' },
76
- }, {
77
- path: 'addrole',
78
- meta: { title: 'Add Role', icon: 'plus' },
79
- name: 'newrole',
80
- component: () => import('@/views/EditDocument'),
81
- props: { collectionName: 'role', id: 'create' },
82
- }],
83
- },
84
-
85
- {
86
- path: '/list/:collectionName',
87
- component: Layout,
88
- hidden: true,
89
- name: 'Data',
90
- meta: { title: 'Data', icon: 'database' },
91
- children: [{
92
- path: '',
93
- name: ':collectionName',
94
- component: () => import('@/views/ListDocuments2'),
95
- props: route => ({ collectionName: route.params.collectionName }),
96
- meta: { title: capitalize(name) }
97
- }]
98
- },
99
-
100
- {
101
- path: '/manage/permissions',
102
- component: Layout,
103
- name: 'permissions',
104
- meta: { title: 'Manage' },
105
- children: [
106
- {
107
- path: '',
108
- name: 'permissions',
109
- component: () => import('@/views/ManagePermissions'),
110
- meta: { title: 'Permissions' }
111
- }
112
- ]
113
- },
114
-
115
- {
116
- path: '/dev',
117
- component: Layout,
118
- meta: { title: 'Dev', icon: 'flask' },
119
- name: 'Dev',
120
- children: [
121
- {
122
- path: '',
123
- name: '',
124
- component: () => import('@/views/Dev'),
125
- meta: { title: '' },
126
- hidden: true,
127
- },
128
- {
129
- path: 'listeners',
130
- name: 'listeners',
131
- component: () => import('@/views/ManageListeners'),
132
- meta: { title: 'Listeners' }
133
- },
134
- {
135
- path: 'middleware',
136
- name: 'middleware',
137
- component: () => import('@/views/ManageMiddleware'),
138
- meta: { title: 'Middleware' }
139
- }, {
140
- path: 'requestlogs',
141
- meta: { title: 'Request Logs', icon: 'diary' },
142
- name: 'requestlogs',
143
- component: () => import('@/views/ListDocuments2'),
144
- props: { collectionName: 'requestlog', columns: ['method', 'url', 'req.ip', 'user', 'res.message', 'res.statusCode', 'res.headers.content-length'] },
145
- }, {
146
- path: 'viewrequest/:requestId',
147
- hidden: true,
148
- meta: { title: 'View Request', icon: 'diary' },
149
- name: 'viewrequest',
150
- component: () => import('@/views/ViewRequest'),
151
- }, {
152
- path: '/edit/collection',
153
- component: Layout,
154
- name: 'Schema',
155
- hidden: true,
156
- meta: { title: 'Schemas', icon: 'cog' },
157
- children: [{
158
- hidden: true,
159
- path: '/:collectionName',
160
- name: name,
161
- meta: { title: capitalize(name) }
162
- }]
163
- },
164
- ]
165
- },
166
-
167
- {
168
- path: 'external-link',
169
- component: Layout,
170
- children: [
171
- {
172
- path: 'https://github.com/thomas4019/expressa',
173
- meta: { title: 'Expressa Docs', icon: 'link' }
174
- }
175
- ]
176
- },
177
-
178
- { path: '*', redirect: '/404', hidden: true }
179
- ]
180
-
181
- export default new Router({
182
- // mode: 'history',
183
- scrollBehavior: () => ({ y: 0 }),
184
- routes: constantRouterMap
185
- })
1
+ import Vue from 'vue'
2
+ import Router from 'vue-router'
3
+
4
+ // in development-env not use lazy-loading, because lazy-loading too many pages will cause webpack hot update too slow. so only in production use lazy-loading;
5
+ // detail: https://panjiachen.github.io/vue-element-admin-site/#/lazy-loading
6
+
7
+ Vue.use(Router)
8
+
9
+ /* Layout */
10
+ import Layout from '../views/layout/Layout'
11
+
12
+ const capitalize = (s) => {
13
+ if (typeof s !== 'string') return ''
14
+ return s.charAt(0).toUpperCase() + s.slice(1)
15
+ }
16
+
17
+ /**
18
+ * hidden: true if `hidden:true` will not show in the sidebar(default is false)
19
+ * alwaysShow: true if set true, will always show the root menu, whatever its child routes length
20
+ * if not set alwaysShow, only more than one route under the children
21
+ * it will becomes nested mode, otherwise not show the root menu
22
+ * redirect: noredirect if `redirect:noredirect` will no redirect in the breadcrumb
23
+ * name:'router-name' the name is used by <keep-alive> (must set!!!)
24
+ * meta : {
25
+ title: 'title' the name show in submenu and breadcrumb (recommend set)
26
+ icon: 'svg-name' the icon show in the sidebar,
27
+ }
28
+ **/
29
+
30
+ export const constantRouterMap = [
31
+ { path: '/login', component: () => import('@/views/login/index'), hidden: true },
32
+ { path: '/install', component: () => import('@/views/Install'), hidden: true },
33
+ { path: '/404', component: () => import('@/views/404'), hidden: true },
34
+
35
+ {
36
+ path: '/',
37
+ component: Layout,
38
+ redirect: '/home',
39
+ name: 'Home',
40
+ meta: { title: 'Home', icon: 'home' },
41
+ children: [{
42
+ path: 'home',
43
+ meta: { title: 'Home', icon: 'home' },
44
+ component: () => import('@/views/Home')
45
+ }, {
46
+ path: '/edit/:collectionName/:id',
47
+ component: () => import('@/views/EditDocument'),
48
+ hidden: true
49
+ }]
50
+ },
51
+
52
+ {
53
+ path: '/users',
54
+ redirect: '/users/list',
55
+ component: Layout,
56
+ name: 'Users',
57
+ meta: { title: 'People', icon: 'users-alt' },
58
+ children: [{
59
+ path: 'list',
60
+ meta: { title: 'Users', icon: 'users-alt' },
61
+ name: 'users2',
62
+ component: () => import('@/views/ListDocuments2'),
63
+ props: { collectionName: 'users' },
64
+ }, {
65
+ path: 'add',
66
+ meta: { title: 'Add User', icon: 'plus' },
67
+ name: 'newuser',
68
+ component: () => import('@/views/EditDocument'),
69
+ props: { collectionName: 'users', id: 'create' },
70
+ }, {
71
+ path: 'role',
72
+ meta: { title: 'Roles', icon: 'shield-check' },
73
+ name: 'role',
74
+ component: () => import('@/views/ListDocuments2'),
75
+ props: { collectionName: 'role' },
76
+ }, {
77
+ path: 'addrole',
78
+ meta: { title: 'Add Role', icon: 'plus' },
79
+ name: 'newrole',
80
+ component: () => import('@/views/EditDocument'),
81
+ props: { collectionName: 'role', id: 'create' },
82
+ }],
83
+ },
84
+
85
+ {
86
+ path: '/list/:collectionName',
87
+ component: Layout,
88
+ hidden: true,
89
+ name: 'Data',
90
+ meta: { title: 'Data', icon: 'database' },
91
+ children: [{
92
+ path: '',
93
+ name: ':collectionName',
94
+ component: () => import('@/views/ListDocuments2'),
95
+ props: route => ({ collectionName: route.params.collectionName }),
96
+ meta: { title: capitalize(name) }
97
+ }]
98
+ },
99
+
100
+ {
101
+ path: '/manage/permissions',
102
+ component: Layout,
103
+ name: 'permissions',
104
+ meta: { title: 'Manage', icon: 'shield-check' },
105
+ children: [
106
+ {
107
+ path: '',
108
+ name: 'permissions',
109
+ component: () => import('@/views/ManagePermissions'),
110
+ meta: { title: 'Permissions' }
111
+ }
112
+ ]
113
+ },
114
+
115
+ {
116
+ path: '/dev',
117
+ component: Layout,
118
+ meta: { title: 'Dev', icon: 'flask' },
119
+ name: 'Dev',
120
+ children: [
121
+ {
122
+ path: '',
123
+ name: '',
124
+ component: () => import('@/views/Dev'),
125
+ meta: { title: '' },
126
+ hidden: true,
127
+ },
128
+ {
129
+ path: 'listeners',
130
+ name: 'listeners',
131
+ component: () => import('@/views/ManageListeners'),
132
+ meta: { title: 'Listeners' }
133
+ },
134
+ {
135
+ path: 'middleware',
136
+ name: 'middleware',
137
+ component: () => import('@/views/ManageMiddleware'),
138
+ meta: { title: 'Middleware' }
139
+ }, {
140
+ path: 'requestlogs',
141
+ meta: { title: 'Request Logs', icon: 'diary' },
142
+ name: 'requestlogs',
143
+ component: () => import('@/views/ListDocuments2'),
144
+ props: { collectionName: 'requestlog', columns: ['method', 'url', 'req.ip', 'user', 'res.message', 'res.statusCode', 'res.headers.content-length'] },
145
+ }, {
146
+ path: 'viewrequest/:requestId',
147
+ hidden: true,
148
+ meta: { title: 'View Request', icon: 'diary' },
149
+ name: 'viewrequest',
150
+ component: () => import('@/views/ViewRequest'),
151
+ }, {
152
+ path: '/edit/collection',
153
+ component: Layout,
154
+ name: 'Schema',
155
+ hidden: true,
156
+ meta: { title: 'Schemas', icon: 'cog' },
157
+ children: [{
158
+ hidden: true,
159
+ path: '/:collectionName',
160
+ name: name,
161
+ meta: { title: capitalize(name) }
162
+ }]
163
+ },
164
+ ]
165
+ },
166
+
167
+ {
168
+ path: 'external-link',
169
+ component: Layout,
170
+ children: [
171
+ {
172
+ path: 'https://github.com/thomas4019/expressa',
173
+ meta: { title: 'Expressa Docs', icon: 'link' }
174
+ }
175
+ ]
176
+ },
177
+
178
+ { path: '*', redirect: '/404', hidden: true }
179
+ ]
180
+
181
+ export default new Router({
182
+ // mode: 'history',
183
+ scrollBehavior: () => ({ y: 0 }),
184
+ routes: constantRouterMap
185
+ })
@@ -155,12 +155,12 @@ export default {
155
155
  return Object.keys(this.searchFilters).reduce((filter, fieldName) => {
156
156
  const searchKeyword = this.searchFilters[fieldName]
157
157
 
158
- if (!searchKeyword) {
158
+ const fieldtype = this.getFieldType(fieldName)
159
+
160
+ if (!searchKeyword || fieldtype === 'custom') {
159
161
  return filter
160
162
  }
161
163
 
162
- const fieldtype = this.getFieldType(fieldName)
163
-
164
164
  const queryBuilder = this.getQueryBuilder(fieldtype)
165
165
 
166
166
  return {
@@ -221,9 +221,31 @@ export default {
221
221
  const columns = this.columns || (this.collection.admin && this.collection.admin.columns)
222
222
  const info = (await request({ url: `/${this.collectionName}/`, params })).data
223
223
  this.count = info.itemsTotal
224
- this.data = info.data
224
+ this.data = this.applyCustomColumnFilter(info.data)
225
225
  this.listedProperties = columns || Object.keys(this.schema.properties)
226
226
  },
227
+ applyCustomColumnFilter(tableData) {
228
+ const customColumnSearches = Object.keys(this.searchFilters)
229
+ .filter((fieldName) => this.getFieldType(fieldName) === 'custom')
230
+
231
+ return tableData.filter((row) => {
232
+ return customColumnSearches.every(fieldName => {
233
+ const searchKeyword = this.searchFilters[fieldName]
234
+
235
+ if (!searchKeyword) {
236
+ return true
237
+ }
238
+
239
+ const stringified = row[fieldName].toString()
240
+
241
+ if (this.exactSearches[fieldName]) {
242
+ return stringified === searchKeyword
243
+ } else {
244
+ return stringified.toLowerCase().includes(searchKeyword.toLowerCase())
245
+ }
246
+ })
247
+ })
248
+ },
227
249
  downloadCSV(data = this.data) {
228
250
  const collection = this.collectionName
229
251
  let text = this.listedProperties.map((name) => '"' + name + '"').join(',') + '\n'
@@ -252,11 +274,11 @@ export default {
252
274
  page += 1
253
275
  }
254
276
 
255
- this.downloadCSV(rows)
277
+ this.downloadCSV(this.applyCustomColumnFilter(rows))
256
278
  },
257
279
  getFieldType(fieldName) {
258
- return this.schema.properties[fieldName] &&
259
- this.schema.properties[fieldName].type
280
+ return (this.schema.properties[fieldName] &&
281
+ this.schema.properties[fieldName].type) || 'custom'
260
282
  },
261
283
  getQueryBuilder(fieldType) {
262
284
  const queryBuilders = {
@@ -71,12 +71,18 @@ exports.init = async function (api) {
71
71
  try {
72
72
  const admin = await api.db.role.get('Admin')
73
73
  collectionPermissions(data._id).forEach(function (permission) {
74
- admin.permissions[permission] = 1
74
+ if (admin.permissions[permission] == null) {
75
+ admin.permissions[permission] = 1
76
+ }
75
77
  })
76
78
  collectionOwnerPermissions(data._id).forEach(function (permission) {
77
- delete admin.permissions[permission]
78
79
  if (data.documentsHaveOwners) {
79
- admin.permissions[permission] = 1
80
+ if (admin.permissions[permission] == null) {
81
+ admin.permissions[permission] = 1
82
+ }
83
+ }
84
+ else {
85
+ delete admin.permissions[permission]
80
86
  }
81
87
  })
82
88
  await api.db.role.update('Admin', admin)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expressa",
3
- "version": "1.0.5",
3
+ "version": "1.1.3",
4
4
  "description": "API framework using JSON schemas",
5
5
  "main": "index.js",
6
6
  "repository": "https://github.com/thomas4019/expressa",
package/util.js CHANGED
@@ -230,8 +230,8 @@ exports.createLogEntry = function (req, res) {
230
230
  },
231
231
  res: {
232
232
  statusCode: res.statusCode,
233
- requestId: res._headers['x-request-id'],
234
- headers: res._headers,
233
+ requestId: res.getHeader('x-request-id'),
234
+ headers: res.getHeaders(),
235
235
  message: req.returnedError ? req.returnedError.message : undefined,
236
236
  },
237
237
  meta: {
@@ -1 +0,0 @@
1
- h3 textarea{resize:both}.jsoneditor-vue button.btn{font-size:14px!important;padding:3px}.jsoneditor-vue .form-control-label,label{font-weight:700}.jsoneditor-vue input[type=checkbox]{margin-right:5px;margin-top:3px}.error-message[data-v-3c5b79e9]{color:red}
@@ -1 +0,0 @@
1
- h3 textarea{resize:both}.jsoneditor-vue button.btn{font-size:14px!important;padding:3px}.jsoneditor-vue .form-control-label,label{font-weight:700}.jsoneditor-vue input[type=checkbox]{margin-right:5px;margin-top:3px}.comment-link{margin-top:-15px}.error-message{color:red}
@@ -1 +0,0 @@
1
- .el-table[data-v-a8e6aab2] th{background-color:#343a40!important;border-color:#454d55;color:#fff}