@live-change/comment-service 0.8.35
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/comment.js +217 -0
- package/definition.js +12 -0
- package/index.js +12 -0
- package/package.json +29 -0
package/comment.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import App from '@live-change/framework'
|
|
2
|
+
const app = App.app()
|
|
3
|
+
|
|
4
|
+
import definition from './definition.js'
|
|
5
|
+
const config = definition.config
|
|
6
|
+
|
|
7
|
+
import { encodeDate } from '@live-change/uid'
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
contentObject = false,
|
|
11
|
+
commentProperties = {},
|
|
12
|
+
adminRoles = ['administrator', 'admin'],
|
|
13
|
+
moderatorRoles = ['administrator', 'admin', 'moderator'],
|
|
14
|
+
editExpire = 1000 * 60 * 60 * 15 // 15 minutes
|
|
15
|
+
} = config
|
|
16
|
+
const {
|
|
17
|
+
readAccessControl,
|
|
18
|
+
createAccessControl,
|
|
19
|
+
updateAccessControl,
|
|
20
|
+
deleteAccessControl,
|
|
21
|
+
} = config
|
|
22
|
+
const {
|
|
23
|
+
readAccess = readAccessControl ? undefined
|
|
24
|
+
: () => true,
|
|
25
|
+
createAccess = createAccessControl ? undefined
|
|
26
|
+
: () => true,
|
|
27
|
+
updateAccess = updateAccessControl ? undefined
|
|
28
|
+
: ({ comment }, { client, visibilityTest }) => {
|
|
29
|
+
if(visibilityTest) return true
|
|
30
|
+
if(client.roles.some(role => adminRoles.includes(role))) return true
|
|
31
|
+
if(!editExpire || Date.now() - new Date(comment.createdAt).getDate() > editExpire) return false
|
|
32
|
+
if(comment.authorType === 'session_Session' && comment.author === client.session) return true
|
|
33
|
+
if(comment.authorType === 'user_User' && comment.author === client.user) return true
|
|
34
|
+
return false
|
|
35
|
+
},
|
|
36
|
+
deleteAccess = (params, { client }) =>
|
|
37
|
+
client.roles.some(role => adminRoles.includes(role)) || client.roles.some(role => moderatorRoles.includes(role))
|
|
38
|
+
} = config
|
|
39
|
+
|
|
40
|
+
const Comment = definition.model({
|
|
41
|
+
name: 'Comment',
|
|
42
|
+
itemOfAny: {
|
|
43
|
+
to: 'cause',
|
|
44
|
+
readAccess,
|
|
45
|
+
createAccess,
|
|
46
|
+
updateAccess,
|
|
47
|
+
deleteAccess,
|
|
48
|
+
readAccessControl,
|
|
49
|
+
createAccessControl,
|
|
50
|
+
updateAccessControl,
|
|
51
|
+
deleteAccessControl
|
|
52
|
+
},
|
|
53
|
+
properties: {
|
|
54
|
+
content: contentObject ? {
|
|
55
|
+
type: Object, // TODO: prosemirror based validation
|
|
56
|
+
validation: ['nonEmpty']
|
|
57
|
+
} : {
|
|
58
|
+
type: String,
|
|
59
|
+
validation: ['nonEmpty']
|
|
60
|
+
},
|
|
61
|
+
createdAt: {
|
|
62
|
+
default: () => new Date()
|
|
63
|
+
},
|
|
64
|
+
updatedAt: {
|
|
65
|
+
updated: () => new Date()
|
|
66
|
+
},
|
|
67
|
+
...commentProperties
|
|
68
|
+
},
|
|
69
|
+
saveAuthor: true,
|
|
70
|
+
saveUpdater: true,
|
|
71
|
+
indexes: {
|
|
72
|
+
byAuthor: {
|
|
73
|
+
property: ['authorType', 'author']
|
|
74
|
+
},
|
|
75
|
+
byRoot: {
|
|
76
|
+
function: async function(input, output, { tableName }) {
|
|
77
|
+
async function findRoot(object){
|
|
78
|
+
let current = object
|
|
79
|
+
while(current) {
|
|
80
|
+
if(current.causeType !== tableName) return `"${current.causeType}":"${current.cause}"`
|
|
81
|
+
current = await input.table(tableName).object(current.cause).get()
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
await input.table(tableName).onChange(async (obj, oldObj) => {
|
|
85
|
+
const id = obj?.id || oldObj?.id
|
|
86
|
+
const root = obj ? await findRoot(obj) : []
|
|
87
|
+
const oldRoot = oldObj ? await findRoot(oldObj) : []
|
|
88
|
+
//console.log("ROOT", id, oldRoot, '=>', root)
|
|
89
|
+
if(root !== oldRoot) {
|
|
90
|
+
if(oldRoot) {
|
|
91
|
+
await output.change(null, { id: `${oldRoot}_${id}`, to: id })
|
|
92
|
+
}
|
|
93
|
+
if(root) {
|
|
94
|
+
await output.change({ id: `${root}_${id}`, to: id }, null)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
},
|
|
99
|
+
parameters: {
|
|
100
|
+
tableName: definition.name + '_Comment'
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
byRootAndDates: {
|
|
104
|
+
function: async function(input, output, { tableName }) {
|
|
105
|
+
async function findRoot(object) {
|
|
106
|
+
let current = object
|
|
107
|
+
const dates = []
|
|
108
|
+
while(current) {
|
|
109
|
+
if(current.causeType !== tableName)
|
|
110
|
+
return `"${current.causeType}":"${current.cause}:${dates.join('-')}"`
|
|
111
|
+
current = await input.table(tableName).object(current.cause).get()
|
|
112
|
+
if(current.causeType === tableName) {
|
|
113
|
+
dates.push(encodeDate(current.createdAt))
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
await input.table(tableName).onChange(async (obj, oldObj) => {
|
|
118
|
+
const id = obj?.id || oldObj?.id
|
|
119
|
+
const root = obj ? await findRoot(obj) : []
|
|
120
|
+
const oldRoot = oldObj ? await findRoot(oldObj) : []
|
|
121
|
+
//console.log("ROOT", id, oldRoot, '=>', root)
|
|
122
|
+
if(root !== oldRoot) {
|
|
123
|
+
if(oldRoot) {
|
|
124
|
+
await output.change(null, { id: `${oldRoot}_${id}`, to: id })
|
|
125
|
+
}
|
|
126
|
+
if(root) {
|
|
127
|
+
await output.change({ id: `${root}_${id}`, to: id }, null)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
})
|
|
131
|
+
},
|
|
132
|
+
parameters: {
|
|
133
|
+
tableName: definition.name + '_Comment'
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
definition.view({
|
|
140
|
+
name: 'commentsByAuthor',
|
|
141
|
+
internal: true,
|
|
142
|
+
properties: {
|
|
143
|
+
authorType: {
|
|
144
|
+
type: String
|
|
145
|
+
},
|
|
146
|
+
author: {
|
|
147
|
+
type: String
|
|
148
|
+
},
|
|
149
|
+
...App.rangeProperties
|
|
150
|
+
},
|
|
151
|
+
returns: {
|
|
152
|
+
type: Array,
|
|
153
|
+
of: {
|
|
154
|
+
type: Comment
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
async daoPath(props, { client }) {
|
|
158
|
+
const range = App.extractRange(props)
|
|
159
|
+
if(range.limit === undefined) range.limit = 256
|
|
160
|
+
return Comment.indexRangePath('byAuthor', [authorType, author], { })
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
definition.view({
|
|
165
|
+
name: 'commentsByRoot',
|
|
166
|
+
properties: {
|
|
167
|
+
rootType: {
|
|
168
|
+
type: String,
|
|
169
|
+
validation: ['nonEmpty']
|
|
170
|
+
},
|
|
171
|
+
root: {
|
|
172
|
+
type: String,
|
|
173
|
+
validation: ['nonEmpty']
|
|
174
|
+
},
|
|
175
|
+
...App.rangeProperties
|
|
176
|
+
},
|
|
177
|
+
returns: {
|
|
178
|
+
type: Array,
|
|
179
|
+
of: {
|
|
180
|
+
type: Comment
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
async daoPath(props) {
|
|
184
|
+
const { rootType, root } = props
|
|
185
|
+
const range = App.extractRange(props)
|
|
186
|
+
if(!range.limit) range.limit = 256
|
|
187
|
+
return Comment.indexRangePath('byRoot', [rootType, root], range)
|
|
188
|
+
}
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
definition.view({
|
|
192
|
+
name: 'commentsByRootGroupedByDates',
|
|
193
|
+
properties: {
|
|
194
|
+
rootType: {
|
|
195
|
+
type: String,
|
|
196
|
+
validation: ['nonEmpty']
|
|
197
|
+
},
|
|
198
|
+
root: {
|
|
199
|
+
type: String,
|
|
200
|
+
validation: ['nonEmpty']
|
|
201
|
+
},
|
|
202
|
+
...App.rangeProperties
|
|
203
|
+
},
|
|
204
|
+
returns: {
|
|
205
|
+
type: Array,
|
|
206
|
+
of: {
|
|
207
|
+
type: Comment
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
async daoPath(props) {
|
|
211
|
+
const { rootType, root } = props
|
|
212
|
+
const range = App.extractRange(props)
|
|
213
|
+
if(!range.limit) range.limit = 256
|
|
214
|
+
return Comment.indexRangePath('byRootAndDates', [rootType, root], range)
|
|
215
|
+
}
|
|
216
|
+
})
|
|
217
|
+
|
package/definition.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import App from '@live-change/framework'
|
|
2
|
+
const app = App.app()
|
|
3
|
+
|
|
4
|
+
import relationsPlugin from '@live-change/relations-plugin'
|
|
5
|
+
import accessControlService from '@live-change/access-control-service'
|
|
6
|
+
|
|
7
|
+
const definition = app.createServiceDefinition({
|
|
8
|
+
name: "comment",
|
|
9
|
+
use: [ relationsPlugin, accessControlService ]
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
export default definition
|
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@live-change/comment-service",
|
|
3
|
+
"version": "0.8.35",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "NODE_ENV=test tape tests/*"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/live-change/live-change-stack.git"
|
|
12
|
+
},
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/live-change/live-change-stack/issues"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://github.com/live-change/live-change-stack",
|
|
18
|
+
"author": {
|
|
19
|
+
"email": "michal@laszczewski.pl",
|
|
20
|
+
"name": "Michał Łaszczewski",
|
|
21
|
+
"url": "https://www.viamage.com/"
|
|
22
|
+
},
|
|
23
|
+
"type": "module",
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@live-change/framework": "^0.8.35",
|
|
26
|
+
"@live-change/relations-plugin": "^0.8.35"
|
|
27
|
+
},
|
|
28
|
+
"gitHead": "90fbb746dc7270895daf17b437ca48c0b0a01c01"
|
|
29
|
+
}
|