Compare commits
10 Commits
169278fc1d
...
a2acb7b928
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2acb7b928 | ||
|
|
d787932e45 | ||
|
|
bd214f0423 | ||
|
|
8999ab3272 | ||
|
|
02849a7396 | ||
|
|
07597ad5f2 | ||
|
|
50dbcf60e1 | ||
|
|
acf72d0aa7 | ||
|
|
0516a20351 | ||
|
|
1d6cca58c2 |
193
ActionParams.json
Normal file
193
ActionParams.json
Normal file
@ -0,0 +1,193 @@
|
||||
[
|
||||
{
|
||||
"type": 1,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"webUrl": "String",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 2,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"translation": "VectorArray",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 3,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"rotation": "VectorArray",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 5,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 6,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 7,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 8,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"speed": "Float",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 9,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"startFrame": "Float",
|
||||
"endFrame": "Float",
|
||||
"fps": "Float",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 10,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"repeatCount": "Int",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 11,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 12,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"scale": "VectorArray",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 13,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 14,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 15,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"alpha": "Float",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 16,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"alpha": "Float",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 17,
|
||||
"availableParams": {
|
||||
"squareMoveWidth": "Float",
|
||||
"squareMoveHeight": "Float",
|
||||
"squareMoveTime": "Float",
|
||||
"squareMoveRotationTime": "Float",
|
||||
"clockwise": "Boolean",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 18,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"roundMoveRadius": "Float",
|
||||
"roundMoveStartAngle": "Float",
|
||||
"roundMoveEndAngel": "Float",
|
||||
"resolution": "Float",
|
||||
"clockwise": "Boolean",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 19,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"moveToFaceDistance": "Float",
|
||||
"isAutoReturn": "Boolean",
|
||||
"autoReturnDelay": "Float",
|
||||
"isFaceToMe": "Boolean",
|
||||
"targetID": "Int",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 20,
|
||||
"availableParams": {
|
||||
"duration": "Float",
|
||||
"webUrl": "String",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 21,
|
||||
"availableParams": {
|
||||
"vibrationTime": "Float",
|
||||
"groupNumber": "Int"
|
||||
}
|
||||
},
|
||||
]
|
||||
491
ArModelData.json
Normal file
491
ArModelData.json
Normal file
@ -0,0 +1,491 @@
|
||||
[
|
||||
{
|
||||
"id": 0,
|
||||
"name": "Plane",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": -1,
|
||||
"z": 0
|
||||
},
|
||||
"rotation": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"modelData": {
|
||||
"type": 0,
|
||||
"material": {
|
||||
"contentType": "image/jpeg",
|
||||
"id": "d6350683.jpg",
|
||||
"textureUrl": "https://cdn2.ettoday.net/images/6350/d6350683.jpg"
|
||||
},
|
||||
"params": {
|
||||
"width": 1,
|
||||
"height": 0.815,
|
||||
"isSizeScaleLock": true
|
||||
}
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"actionType": 2,
|
||||
"alpha": 1,
|
||||
"autoReturnDelay": 3,
|
||||
"clockwise": true,
|
||||
"duration": 1,
|
||||
"endFrame": 100,
|
||||
"fps": 24,
|
||||
"groupNumber": 0,
|
||||
"isAutoReturn": true,
|
||||
"isFaceToMe": true,
|
||||
"moveToFaceDistance": 1,
|
||||
"repeatCount": 1,
|
||||
"resolution": 16,
|
||||
"rotation": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"roundMoveEndAngel": 360,
|
||||
"roundMoveRadius": 1,
|
||||
"roundMoveStartAngle": 0,
|
||||
"scale": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"speed": 1,
|
||||
"squareMoveHeight": 1,
|
||||
"squareMoveRotationTime": 0.8,
|
||||
"squareMoveTime": 1,
|
||||
"squareMoveWidth": 1,
|
||||
"startFrame": 0,
|
||||
"targetId": 0,
|
||||
"translation": {
|
||||
"x": 1,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"vibrationTime": 1,
|
||||
"webUrl": ""
|
||||
}
|
||||
],
|
||||
"eventType": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Cube",
|
||||
"position": {
|
||||
"x": 1,
|
||||
"y": -1,
|
||||
"z": 0
|
||||
},
|
||||
"rotation": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"modelData": {
|
||||
"material": {
|
||||
"contentType": "image/jpeg",
|
||||
"id": "d6350683.jpg",
|
||||
"textureUrl": "https://cdn2.ettoday.net/images/6350/d6350683.jpg"
|
||||
},
|
||||
"params": {
|
||||
"width": 0.75,
|
||||
"height": 0.75,
|
||||
"depth": 0.75
|
||||
},
|
||||
"type": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Sphere",
|
||||
"position": {
|
||||
"x": 2,
|
||||
"y": -1,
|
||||
"z": 0
|
||||
},
|
||||
"rotation": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"modelData": {
|
||||
"type": 2,
|
||||
"material": {
|
||||
"contentType": "image/jpeg",
|
||||
"id": "d6350683.jpg",
|
||||
"textureUrl": "https://cdn2.ettoday.net/images/6350/d6350683.jpg"
|
||||
},
|
||||
"params": {
|
||||
"availableRange": 20,
|
||||
"isDoubleSided": true,
|
||||
"isFaceMe": false,
|
||||
"isHidden": false,
|
||||
"isIgnore": false,
|
||||
"isOcclusion": false,
|
||||
"radius": 0.45
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Cylinder",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"rotation": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"modelData": {
|
||||
"material": {
|
||||
"contentType": "image/jpeg",
|
||||
"id": "d6350683.jpg",
|
||||
"textureUrl": "https://cdn2.ettoday.net/images/6350/d6350683.jpg"
|
||||
},
|
||||
"params": {
|
||||
"availableRange": 20,
|
||||
"height": 1,
|
||||
"isDoubleSided": true,
|
||||
"isFaceMe": false,
|
||||
"isHidden": false,
|
||||
"isIgnore": false,
|
||||
"isOcclusion": false,
|
||||
"radius": 0.25
|
||||
},
|
||||
"type": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Model3D",
|
||||
"position": {
|
||||
"x": 1,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"rotation": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"modelData": {
|
||||
"material": {
|
||||
"contentType": "model/gltf-binary",
|
||||
"id": "spiderbot.glb",
|
||||
"textureUrl": "https://www.ray650128.com/spiderbot.glb"
|
||||
},
|
||||
"params": {
|
||||
"availableRange": 20,
|
||||
"isDoubleSided": true,
|
||||
"isFaceMe": false,
|
||||
"isHidden": false,
|
||||
"isIgnore": false,
|
||||
"isMultiplyPlane": false,
|
||||
"isOcclusion": false,
|
||||
"modelEndFrame": 100,
|
||||
"modelFPS": 24,
|
||||
"modelStartFrame": 0,
|
||||
"multiplyNumber": 10,
|
||||
"multiplyRadius": 1,
|
||||
"multiplyRange": 1
|
||||
},
|
||||
"type": 4
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "Video1",
|
||||
"position": {
|
||||
"x": 1,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"rotation": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"modelData": {
|
||||
"material": {
|
||||
"contentType": "video/mpeg4",
|
||||
"id": "ker1.mp4",
|
||||
"textureUrl": "https://www.ray650128.com/video/ker1.mp4"
|
||||
},
|
||||
"params": {
|
||||
"availableRange": 20,
|
||||
"hueAngle": 120,
|
||||
"hueRange": 20,
|
||||
"isDoubleSided": true,
|
||||
"isFaceMe": false,
|
||||
"isHidden": false,
|
||||
"isIgnore": false,
|
||||
"isOcclusion": false,
|
||||
"isPlayWhenReady": true,
|
||||
"isRepeat": true,
|
||||
"saturation": 80,
|
||||
"videoThumbnail": "https://cdn2.ettoday.net/images/6350/d6350683.jpg"
|
||||
},
|
||||
"type": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "Video2",
|
||||
"position": {
|
||||
"x": 2,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"rotation": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"modelData": {
|
||||
"material": {
|
||||
"contentType": "video/mpeg4",
|
||||
"id": "ker2.mp4",
|
||||
"textureUrl": "https://www.ray650128.com/video/ker2.mp4"
|
||||
},
|
||||
"params": {
|
||||
"availableRange": 20,
|
||||
"hueAngle": 124,
|
||||
"hueRange": 20,
|
||||
"isDoubleSided": true,
|
||||
"isFaceMe": false,
|
||||
"isHidden": false,
|
||||
"isIgnore": false,
|
||||
"isOcclusion": false,
|
||||
"saturation": 80
|
||||
},
|
||||
"type": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "Video3",
|
||||
"position": {
|
||||
"x": 3,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"rotation": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"modelData": {
|
||||
"material": {
|
||||
"contentType": "video/mpeg4",
|
||||
"id": "hou1.mp4",
|
||||
"textureUrl": "https://www.ray650128.com/video/hou1.mp4"
|
||||
},
|
||||
"params": {
|
||||
"availableRange": 20,
|
||||
"hueAngle": 35,
|
||||
"hueRange": 20,
|
||||
"isDoubleSided": true,
|
||||
"isFaceMe": false,
|
||||
"isHidden": false,
|
||||
"isIgnore": false,
|
||||
"isOcclusion": false,
|
||||
"saturation": 50
|
||||
},
|
||||
"type": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "Light",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"rotation": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"modelData": {
|
||||
"params": {
|
||||
"availableRange": 20,
|
||||
"color": {
|
||||
"r": 1,
|
||||
"g": 1,
|
||||
"b": 0,
|
||||
"a": 0
|
||||
},
|
||||
"lightIntensity": 25000
|
||||
},
|
||||
"type": 100
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "MultiFace",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 1,
|
||||
"z": 0
|
||||
},
|
||||
"rotation": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"modelData": {
|
||||
"material": {
|
||||
"contentTypes": [
|
||||
"image/jpeg",
|
||||
"image/jpeg",
|
||||
"image/jpeg",
|
||||
"image/jpeg",
|
||||
"image/jpeg",
|
||||
"image/jpeg",
|
||||
"image/jpeg",
|
||||
"image/jpeg",
|
||||
"image/jpeg",
|
||||
"image/jpeg",
|
||||
"image/jpeg",
|
||||
"image/jpeg",
|
||||
"image/jpeg",
|
||||
"image/jpeg",
|
||||
"image/jpeg"
|
||||
],
|
||||
"textureUrls": [
|
||||
"https://cdn2.ettoday.net/images/6350/d6350683.jpg",
|
||||
"https://cdn2.ettoday.net/images/6350/d6350683.jpg",
|
||||
"https://cdn2.ettoday.net/images/6350/d6350683.jpg",
|
||||
"https://cdn2.ettoday.net/images/6350/d6350683.jpg",
|
||||
"https://cdn2.ettoday.net/images/6350/d6350683.jpg",
|
||||
"https://cdn2.ettoday.net/images/6350/d6350683.jpg",
|
||||
"https://cdn2.ettoday.net/images/6350/d6350683.jpg",
|
||||
"https://cdn2.ettoday.net/images/6350/d6350683.jpg",
|
||||
"https://cdn2.ettoday.net/images/6350/d6350683.jpg",
|
||||
"https://cdn2.ettoday.net/images/6350/d6350683.jpg",
|
||||
"https://cdn2.ettoday.net/images/6350/d6350683.jpg",
|
||||
"https://cdn2.ettoday.net/images/6350/d6350683.jpg",
|
||||
"https://cdn2.ettoday.net/images/6350/d6350683.jpg",
|
||||
"https://cdn2.ettoday.net/images/6350/d6350683.jpg",
|
||||
"https://cdn2.ettoday.net/images/6350/d6350683.jpg"
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"levelAngles": [
|
||||
45,
|
||||
0,
|
||||
-45
|
||||
],
|
||||
"levelBorders": [
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
],
|
||||
"levelCount": 3,
|
||||
"planeBorder": 0.1,
|
||||
"planeCount": 5,
|
||||
"speed": 1
|
||||
},
|
||||
"type": 6
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "Sign",
|
||||
"position": {
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 0
|
||||
},
|
||||
"rotation": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"scale": {
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
"z": 1
|
||||
},
|
||||
"modelData": {
|
||||
"material": {
|
||||
"contentType": "image/jpeg",
|
||||
"id": "d6350683.jpg",
|
||||
"textureUrl": "https://cdn2.ettoday.net/images/6350/d6350683.jpg"
|
||||
},
|
||||
"params": {
|
||||
"availableRange": 20,
|
||||
"signIcon": "https://cdn2.ettoday.net/images/6350/d6350683.jpg",
|
||||
"signName": "0.0/",
|
||||
"signTextColor": {
|
||||
"r": 1,
|
||||
"g": 0,
|
||||
"b": 0,
|
||||
"a": 0
|
||||
}
|
||||
},
|
||||
"type": 7
|
||||
}
|
||||
}
|
||||
]
|
||||
151
ModelParams.json
Normal file
151
ModelParams.json
Normal file
@ -0,0 +1,151 @@
|
||||
[
|
||||
{
|
||||
"type": 0,
|
||||
"availableParams": {
|
||||
"isFaceMe": "Boolean",
|
||||
"isIgnore": "Boolean",
|
||||
"isHidden": "Boolean",
|
||||
"isDoubleSided": "Boolean",
|
||||
"isOcclusion": "Boolean",
|
||||
"availableRange": "Float",
|
||||
"width": "Float",
|
||||
"height": "Float",
|
||||
"isSizeScaleLock": "Float"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"availableParams": {
|
||||
"isFaceMe": "Boolean",
|
||||
"isIgnore": "Boolean",
|
||||
"isHidden": "Boolean",
|
||||
"isDoubleSided": "Boolean",
|
||||
"isOcclusion": "Boolean",
|
||||
"availableRange": "Float",
|
||||
"width": "Float",
|
||||
"height": "Float",
|
||||
"depth": "Float"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 2,
|
||||
"availableParams": {
|
||||
"isFaceMe": "Boolean",
|
||||
"isIgnore": "Boolean",
|
||||
"isHidden": "Boolean",
|
||||
"isDoubleSided": "Boolean",
|
||||
"isOcclusion": "Boolean",
|
||||
"availableRange": "Float",
|
||||
"radius": "Float"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 3,
|
||||
"availableParams": {
|
||||
"isFaceMe": "Boolean",
|
||||
"isIgnore": "Boolean",
|
||||
"isHidden": "Boolean",
|
||||
"isDoubleSided": "Boolean",
|
||||
"isOcclusion": "Boolean",
|
||||
"availableRange": "Float",
|
||||
"radius": "Float",
|
||||
"height": "Float"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 4,
|
||||
"availableParams": {
|
||||
"isFaceMe": "Boolean",
|
||||
"isIgnore": "Boolean",
|
||||
"isHidden": "Boolean",
|
||||
"isDoubleSided": "Boolean",
|
||||
"isOcclusion": "Boolean",
|
||||
"availableRange": "Float",
|
||||
"modelAnimSpeed": "Float",
|
||||
"modelStartFrame": "Float",
|
||||
"modelEndFrame": "Float",
|
||||
"modelFPS": "Float",
|
||||
"multiplyNumber": "Int",
|
||||
"multiplyRadius": "Float",
|
||||
"multiplyRange": "Float",
|
||||
"isMultiplyPlane": "Boolean"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 5,
|
||||
"availableParams": {
|
||||
"isFaceMe": "Boolean",
|
||||
"isIgnore": "Boolean",
|
||||
"isHidden": "Boolean",
|
||||
"isDoubleSided": "Boolean",
|
||||
"isOcclusion": "Boolean",
|
||||
"availableRange": "Float",
|
||||
"hueAngle": "Float",
|
||||
"hueRange": "Float",
|
||||
"saturation": "Float",
|
||||
"isPlayWhenReady": "Boolean",
|
||||
"isRepeat": "Boolean",
|
||||
"videoThumbnail": "String"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 6,
|
||||
"availableParams": {
|
||||
"isFaceMe": "Boolean",
|
||||
"isIgnore": "Boolean",
|
||||
"isHidden": "Boolean",
|
||||
"isDoubleSided": "Boolean",
|
||||
"isOcclusion": "Boolean",
|
||||
"availableRange": "Float",
|
||||
"levelCount": "Int",
|
||||
"levelBorders": "FloatArray",
|
||||
"levelAngles": "FloatArray",
|
||||
"planeCount": "Int",
|
||||
"planeBorder": "Boolean",
|
||||
"speed": "Float",
|
||||
"isClockwise": "Boolean"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 7,
|
||||
"availableParams": {
|
||||
"isFaceMe": "Boolean",
|
||||
"isIgnore": "Boolean",
|
||||
"isHidden": "Boolean",
|
||||
"isDoubleSided": "Boolean",
|
||||
"isOcclusion": "Boolean",
|
||||
"availableRange": "Float",
|
||||
"width": "Float",
|
||||
"height": "Float",
|
||||
"signIcon": "String",
|
||||
"signName": "String",
|
||||
"signTextColor": "ColorArray"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 100,
|
||||
"availableParams": {
|
||||
"isFaceMe": "Boolean",
|
||||
"isIgnore": "Boolean",
|
||||
"isHidden": "Boolean",
|
||||
"isDoubleSided": "Boolean",
|
||||
"isOcclusion": "Boolean",
|
||||
"availableRange": "Float",
|
||||
"lightIntensity": "Float",
|
||||
"color": "ColorArray"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": 101,
|
||||
"availableParams": {
|
||||
"isFaceMe": "Boolean",
|
||||
"isIgnore": "Boolean",
|
||||
"isHidden": "Boolean",
|
||||
"isDoubleSided": "Boolean",
|
||||
"isOcclusion": "Boolean",
|
||||
"availableRange": "Float",
|
||||
"lightIntensity": "Float",
|
||||
"color": "ColorArray"
|
||||
}
|
||||
}
|
||||
]
|
||||
131
NewArModelData.json
Normal file
131
NewArModelData.json
Normal file
@ -0,0 +1,131 @@
|
||||
{
|
||||
"id": 0,
|
||||
"name": "TEST",
|
||||
"type": 0,
|
||||
"location": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"rotation": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"scale": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
},
|
||||
"params": {
|
||||
"width": 0.0,
|
||||
"height": 0.0,
|
||||
"depth": 0.0,
|
||||
"radius": 0.0,
|
||||
"isSizeScaleLock": false,
|
||||
"availableRange": 20.0,
|
||||
"isFaceMe": false,
|
||||
"isIgnore": false,
|
||||
"isHidden": false,
|
||||
"isDoubleSided": false,
|
||||
"isOcclusion": false,
|
||||
"modelAnimSpeed": 0.0,
|
||||
"modelStartFrame": 0,
|
||||
"modelEndFrame": 0,
|
||||
"modelFPS": 0.0,
|
||||
"multiplyNumber": 0,
|
||||
"multiplyRadius": 0.0,
|
||||
"multiplyRange": 0.0,
|
||||
"isMultiplyPlane": false,
|
||||
"hueAngle": 0.0,
|
||||
"hueRange": 0.0,
|
||||
"saturation": 0.0,
|
||||
"isPlayWhenReady": false,
|
||||
"isRepeat": true,
|
||||
"videoThumbnail": "",
|
||||
"levelCount": 3,
|
||||
"levelBorders": [0.5, 0.5, 0.5],
|
||||
"levelAngles": [30.0, 0.0, -30.0],
|
||||
"planeCount": 5,
|
||||
"planeBorder": 0.25,
|
||||
"speed": 60,
|
||||
"isClockwise": true,
|
||||
"signIcon": {
|
||||
"textureId": 0,
|
||||
"fileName": "",
|
||||
"materialUrl": "",
|
||||
"contentType": "image/png"
|
||||
},
|
||||
"signName": "",
|
||||
"signTextColor": {
|
||||
"r": 0.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 0.0
|
||||
},
|
||||
"lightIntensity": 1000.0,
|
||||
"color": {
|
||||
"r": 0.0,
|
||||
"g": 0.0,
|
||||
"b": 0.0,
|
||||
"a": 0.0
|
||||
}
|
||||
},
|
||||
"material": [
|
||||
{
|
||||
"textureId": 0,
|
||||
"fileName": "",
|
||||
"materialUrl": "",
|
||||
"contentType": "image/png"
|
||||
}
|
||||
],
|
||||
"events": [
|
||||
{
|
||||
"eventType": 1,
|
||||
"actions": [
|
||||
{
|
||||
"actionType": 2,
|
||||
"alpha": 1,
|
||||
"autoReturnDelay": 3,
|
||||
"clockwise": true,
|
||||
"duration": 1,
|
||||
"endFrame": 100,
|
||||
"fps": 24,
|
||||
"groupNumber": 0,
|
||||
"isAutoReturn": true,
|
||||
"isFaceToMe": true,
|
||||
"moveToFaceDistance": 1,
|
||||
"repeatCount": 1,
|
||||
"resolution": 16,
|
||||
"rotation": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"roundMoveEndAngel": 360,
|
||||
"roundMoveRadius": 1,
|
||||
"roundMoveStartAngle": 0,
|
||||
"scale": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"speed": 1,
|
||||
"squareMoveHeight": 1,
|
||||
"squareMoveRotationTime": 0.8,
|
||||
"squareMoveTime": 1,
|
||||
"squareMoveWidth": 1,
|
||||
"startFrame": 0,
|
||||
"targetId": 0,
|
||||
"translation": {
|
||||
"x": 1,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"vibrationTime": 1,
|
||||
"webUrl": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -31,6 +31,8 @@ dependencies {
|
||||
testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version")
|
||||
testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
|
||||
implementation("org.litote.kmongo:kmongo:$kmongo_version")
|
||||
implementation("org.litote.kmongo:kmongo-id-serialization:$kmongo_version")
|
||||
implementation("io.ktor:ktor-server-auth-jvm:$ktor_version")
|
||||
implementation("io.ktor:ktor-server-auth-jwt-jvm:$ktor_version")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0")
|
||||
}
|
||||
@ -1,32 +1,44 @@
|
||||
package com.ray650128
|
||||
|
||||
import com.ray650128.dto.UserDto
|
||||
import com.ray650128.model.User
|
||||
import com.ray650128.plugins.configureRouting
|
||||
import com.ray650128.plugins.configureSerialization
|
||||
import com.ray650128.model.pojo.User
|
||||
import com.ray650128.plugins.configureUserRouting
|
||||
import com.ray650128.plugins.configureArMaterialRouting
|
||||
import com.ray650128.plugins.configureArModelRouting
|
||||
import com.ray650128.service.UserService
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.auth.*
|
||||
import io.ktor.server.auth.jwt.*
|
||||
import io.ktor.server.engine.*
|
||||
import io.ktor.server.netty.*
|
||||
import io.ktor.server.plugins.contentnegotiation.*
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.litote.kmongo.id.serialization.IdKotlinXSerializationModule
|
||||
|
||||
fun main() {
|
||||
embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
|
||||
install(ContentNegotiation) {
|
||||
json(
|
||||
Json { serializersModule = IdKotlinXSerializationModule }
|
||||
)
|
||||
}
|
||||
install(Authentication) {
|
||||
jwt {
|
||||
verifier(JwtConfig.verifier)
|
||||
realm = JwtConfig.myRealm
|
||||
validate {
|
||||
val service = UserService()
|
||||
val name = it.payload.getClaim("account").asString()
|
||||
if (name != null) {
|
||||
UserDto(account = name, password = "")
|
||||
service.findByAccount(name)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
configureRouting()
|
||||
configureSerialization()
|
||||
configureUserRouting()
|
||||
configureArMaterialRouting()
|
||||
configureArModelRouting()
|
||||
}.start(wait = true)
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ package com.ray650128
|
||||
import com.auth0.jwt.JWT
|
||||
import com.auth0.jwt.JWTVerifier
|
||||
import com.auth0.jwt.algorithms.Algorithm
|
||||
import com.ray650128.dto.UserDto
|
||||
import com.ray650128.model.pojo.User
|
||||
import java.util.*
|
||||
|
||||
object JwtConfig {
|
||||
@ -21,7 +21,7 @@ object JwtConfig {
|
||||
/**
|
||||
* Produce a token for this combination of name and password
|
||||
*/
|
||||
fun generateToken(user: UserDto): String = JWT.create()
|
||||
fun generateToken(user: User): String = JWT.create()
|
||||
.withSubject("Authentication")
|
||||
.withIssuer(issuer)
|
||||
.withClaim("account", user.account)
|
||||
|
||||
32
src/main/kotlin/com/ray650128/extension/ArModelExtension.kt
Normal file
32
src/main/kotlin/com/ray650128/extension/ArModelExtension.kt
Normal file
@ -0,0 +1,32 @@
|
||||
package com.ray650128.extension
|
||||
|
||||
import com.ray650128.model.pojo.arModel.ArModel
|
||||
import com.ray650128.model.pojo.arModelDto.ArModelDto
|
||||
|
||||
fun ArModel.toDto(): ArModelDto =
|
||||
ArModelDto(
|
||||
_id = this._id.toString(),
|
||||
ownerId = this.ownerId.toString(),
|
||||
name = this.name,
|
||||
position = this.position,
|
||||
rotation = this.rotation,
|
||||
scale = this.scale,
|
||||
modelData = this.modelData.toDto(),
|
||||
events = this.events,
|
||||
childEvents = this.childEvents,
|
||||
createAt = this.createAt,
|
||||
updatedAt = this.updatedAt
|
||||
)
|
||||
|
||||
fun ArModelDto.toArModel(): ArModel =
|
||||
ArModel(
|
||||
name = this.name,
|
||||
position = this.position,
|
||||
rotation = this.rotation,
|
||||
scale = this.scale,
|
||||
modelData = this.modelData.toModelData(),
|
||||
events = this.events,
|
||||
childEvents = this.childEvents,
|
||||
createAt = this.createAt,
|
||||
updatedAt = this.updatedAt
|
||||
)
|
||||
@ -0,0 +1,22 @@
|
||||
package com.ray650128.extension
|
||||
|
||||
import com.ray650128.model.pojo.arModel.ModelData
|
||||
import com.ray650128.model.pojo.arModelDto.ModelDataDto
|
||||
import com.ray650128.service.MaterialService
|
||||
|
||||
fun ModelData.toDto(): ModelDataDto {
|
||||
val service = MaterialService()
|
||||
return ModelDataDto(
|
||||
type = this.type,
|
||||
material = service.findById(this.material.toString()),
|
||||
params = this.params
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fun ModelDataDto.toModelData(): ModelData =
|
||||
ModelData(
|
||||
type = this.type,
|
||||
material = this.material?._id,
|
||||
params = this.params
|
||||
)
|
||||
42
src/main/kotlin/com/ray650128/extension/ResponseExtension.kt
Normal file
42
src/main/kotlin/com/ray650128/extension/ResponseExtension.kt
Normal file
@ -0,0 +1,42 @@
|
||||
package com.ray650128.extension
|
||||
|
||||
import com.ray650128.model.ErrorResponse
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.response.*
|
||||
|
||||
|
||||
suspend fun <T> ApplicationCall.sendCreated(data: T?) {
|
||||
this.respond(
|
||||
status = HttpStatusCode.Created,
|
||||
message = data ?: mapOf("message" to "success.")
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun <T : Any> ApplicationCall.sendSuccess(data: T?) {
|
||||
this.respond(
|
||||
status = HttpStatusCode.OK,
|
||||
message = data ?: mapOf("message" to "success.")
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun ApplicationCall.sendUnauthorized() {
|
||||
this.respond(
|
||||
status = HttpStatusCode.Unauthorized,
|
||||
message = ErrorResponse.UNAUTHORIZED_RESPONSE
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun ApplicationCall.sendBadRequest(errorResponse: ErrorResponse) {
|
||||
this.respond(
|
||||
status = HttpStatusCode.BadRequest,
|
||||
message = errorResponse
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun ApplicationCall.sendNotFound() {
|
||||
this.respond(
|
||||
status = HttpStatusCode.NotFound,
|
||||
message = ErrorResponse.NOT_FOUND_RESPONSE
|
||||
)
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
package com.ray650128.extension
|
||||
|
||||
import com.ray650128.dto.UserDto
|
||||
import com.ray650128.model.User
|
||||
|
||||
fun User.toDto(): UserDto =
|
||||
UserDto(
|
||||
id = this.id.toString(),
|
||||
account = this.account,
|
||||
password = this.password,
|
||||
name = this.name,
|
||||
token = this.token,
|
||||
createAt = this.createAt,
|
||||
updatedAt = this.updatedAt
|
||||
)
|
||||
|
||||
fun UserDto.toUser(): User =
|
||||
User(
|
||||
account = this.account,
|
||||
password = this.password,
|
||||
name = this.name,
|
||||
token = this.token,
|
||||
createAt = this.createAt,
|
||||
updatedAt = this.updatedAt
|
||||
)
|
||||
@ -7,5 +7,6 @@ data class ErrorResponse(val message: String) {
|
||||
companion object {
|
||||
val NOT_FOUND_RESPONSE = ErrorResponse("Person was not found")
|
||||
val BAD_REQUEST_RESPONSE = ErrorResponse("Invalid request")
|
||||
val UNAUTHORIZED_RESPONSE = ErrorResponse("Unauthorized")
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
package com.ray650128.model
|
||||
|
||||
import org.bson.codecs.pojo.annotations.BsonId
|
||||
import org.litote.kmongo.Id
|
||||
|
||||
data class User(
|
||||
@BsonId
|
||||
val id: Id<User>? = null,
|
||||
val account: String,
|
||||
val password: String,
|
||||
var name: String? = null,
|
||||
var token: String? = null,
|
||||
var createAt: Long? = null,
|
||||
var updatedAt: Long? = null
|
||||
)
|
||||
@ -1,4 +1,4 @@
|
||||
package com.ray650128.model
|
||||
package com.ray650128.model.pojo
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
18
src/main/kotlin/com/ray650128/model/pojo/Material.kt
Normal file
18
src/main/kotlin/com/ray650128/model/pojo/Material.kt
Normal file
@ -0,0 +1,18 @@
|
||||
package com.ray650128.model.pojo
|
||||
|
||||
import kotlinx.serialization.Contextual
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.litote.kmongo.Id
|
||||
import org.litote.kmongo.newId
|
||||
|
||||
@Serializable
|
||||
data class Material(
|
||||
@Contextual var _id: Id<Material> = newId(),
|
||||
@Contextual var ownerId: Id<User>? = null,
|
||||
var name: String,
|
||||
var path: String? = null,
|
||||
var contentType: String? = null,
|
||||
var fileTag: ArrayList<String>? = null,
|
||||
var createAt: Long? = null,
|
||||
var updatedAt: Long? = null
|
||||
)
|
||||
8
src/main/kotlin/com/ray650128/model/pojo/NewMaterial.kt
Normal file
8
src/main/kotlin/com/ray650128/model/pojo/NewMaterial.kt
Normal file
@ -0,0 +1,8 @@
|
||||
package com.ray650128.model.pojo
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class NewMaterial(
|
||||
var name: String
|
||||
)
|
||||
@ -1,14 +1,17 @@
|
||||
package com.ray650128.dto
|
||||
package com.ray650128.model.pojo
|
||||
|
||||
import io.ktor.server.auth.*
|
||||
import kotlinx.serialization.Contextual
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.litote.kmongo.Id
|
||||
import org.litote.kmongo.newId
|
||||
|
||||
@Serializable
|
||||
data class UserDto(
|
||||
val id: String? = null,
|
||||
data class User(
|
||||
@Contextual val _id: Id<User>? = newId(),
|
||||
val account: String,
|
||||
val password: String,
|
||||
val name: String? = null,
|
||||
var name: String? = null,
|
||||
var token: String? = null,
|
||||
var createAt: Long? = null,
|
||||
var updatedAt: Long? = null
|
||||
22
src/main/kotlin/com/ray650128/model/pojo/arModel/ArModel.kt
Normal file
22
src/main/kotlin/com/ray650128/model/pojo/arModel/ArModel.kt
Normal file
@ -0,0 +1,22 @@
|
||||
package com.ray650128.model.pojo.arModel
|
||||
|
||||
import com.ray650128.model.pojo.User
|
||||
import kotlinx.serialization.Contextual
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.litote.kmongo.Id
|
||||
import org.litote.kmongo.newId
|
||||
|
||||
@Serializable
|
||||
data class ArModel(
|
||||
@Contextual var _id: Id<ArModel>? = newId(),
|
||||
@Contextual var ownerId: Id<User>? = null,
|
||||
var name: String,
|
||||
var position: Float3,
|
||||
var rotation: Float3,
|
||||
var scale: Float3,
|
||||
var modelData: ModelData,
|
||||
var events: ArrayList<ModelEvent>? = null,
|
||||
var childEvents: HashMap<String, ArrayList<ModelEvent>?>? = null,
|
||||
var createAt: Long? = null,
|
||||
var updatedAt: Long? = null
|
||||
)
|
||||
11
src/main/kotlin/com/ray650128/model/pojo/arModel/Color.kt
Normal file
11
src/main/kotlin/com/ray650128/model/pojo/arModel/Color.kt
Normal file
@ -0,0 +1,11 @@
|
||||
package com.ray650128.model.pojo.arModel
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Color(
|
||||
var r: Float = 0.0f,
|
||||
var g: Float = 0.0f,
|
||||
var b: Float = 0.0f,
|
||||
var a: Float = 0.0f
|
||||
)
|
||||
10
src/main/kotlin/com/ray650128/model/pojo/arModel/Float3.kt
Normal file
10
src/main/kotlin/com/ray650128/model/pojo/arModel/Float3.kt
Normal file
@ -0,0 +1,10 @@
|
||||
package com.ray650128.model.pojo.arModel
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Float3(
|
||||
var x: Float,
|
||||
var y: Float,
|
||||
var z: Float
|
||||
)
|
||||
@ -0,0 +1,44 @@
|
||||
package com.ray650128.model.pojo.arModel
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ModelAction(
|
||||
var actionType: Int,
|
||||
var duration: Float?,
|
||||
var translation: Float3? = null,
|
||||
var rotation: Float3? = null,
|
||||
var scale: Float3? = null,
|
||||
var alpha: Float? = null,
|
||||
|
||||
var webUrl: String? = null,
|
||||
|
||||
var speed: Float? = null,
|
||||
var startFrame: Float? = null,
|
||||
var endFrame: Float? = null,
|
||||
var fps: Float? = null,
|
||||
|
||||
var repeatCount: Int? = null,
|
||||
|
||||
var squareMoveWidth: Float? = null,
|
||||
var squareMoveHeight: Float? = null,
|
||||
var squareMoveTime: Float? = null,
|
||||
var squareMoveRotationTime: Float? = null,
|
||||
|
||||
var clockwise: Boolean? = null,
|
||||
|
||||
var roundMoveRadius: Float? = null,
|
||||
var roundMoveStartAngle: Float? = null,
|
||||
var roundMoveEndAngel: Float? = null,
|
||||
var resolution: Float? = null,
|
||||
|
||||
var moveToFaceDistance: Float? = null,
|
||||
var isAutoReturn: Boolean? = null,
|
||||
var autoReturnDelay: Float? = null,
|
||||
var isFaceToMe: Boolean? = null,
|
||||
|
||||
var vibrationTime: Int? = null,
|
||||
|
||||
var targetId: Int? = null,
|
||||
var groupNumber: Int? = null
|
||||
)
|
||||
@ -0,0 +1,13 @@
|
||||
package com.ray650128.model.pojo.arModel
|
||||
|
||||
import com.ray650128.model.pojo.Material
|
||||
import kotlinx.serialization.Contextual
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.litote.kmongo.Id
|
||||
|
||||
@Serializable
|
||||
data class ModelData(
|
||||
var type: Int = -1,
|
||||
@Contextual var material: Id<Material>? = null,
|
||||
var params: ModelParams
|
||||
)
|
||||
@ -0,0 +1,9 @@
|
||||
package com.ray650128.model.pojo.arModel
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ModelEvent(
|
||||
var eventType: Int,
|
||||
var actions: ArrayList<ModelAction>? = null
|
||||
)
|
||||
@ -0,0 +1,51 @@
|
||||
package com.ray650128.model.pojo.arModel
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ModelParams(
|
||||
var isFaceMe: Boolean = false,
|
||||
var isIgnore: Boolean = false,
|
||||
var isHidden: Boolean = false,
|
||||
var isDoubleSided: Boolean = true,
|
||||
var isOcclusion: Boolean = false,
|
||||
var availableRange: Float = 20f,
|
||||
|
||||
var width: Float? = null,
|
||||
var height: Float? = null,
|
||||
var depth: Float? = null,
|
||||
var radius: Float? = null,
|
||||
var isSizeScaleLock: Boolean? = null,
|
||||
|
||||
var modelAnimSpeed: Float? = null,
|
||||
var modelStartFrame: Float? = null,
|
||||
var modelEndFrame: Float? = null,
|
||||
var modelFPS: Float? = null,
|
||||
|
||||
var multiplyNumber: Int? = null,
|
||||
var multiplyRadius: Float? = null,
|
||||
var multiplyRange: Float? = null,
|
||||
var isMultiplyPlane: Boolean? = null,
|
||||
|
||||
var hueAngle: Float? = null,
|
||||
var hueRange: Float? = null,
|
||||
var saturation: Float? = null,
|
||||
var isPlayWhenReady: Boolean? = null,
|
||||
var isRepeat: Boolean? = null,
|
||||
var videoThumbnail: String? = null,
|
||||
|
||||
var lightIntensity: Float? = null,
|
||||
var color: Color? = null,
|
||||
|
||||
var levelCount: Int? = null,
|
||||
var levelBorders: ArrayList<Float>? = null,
|
||||
var levelAngles: ArrayList<Float>? = null,
|
||||
var planeCount: Int? = null,
|
||||
var planeBorder: Float? = null,
|
||||
var speed: Float? = null,
|
||||
var isClockwise: Boolean? = null,
|
||||
|
||||
var signIcon: String? = null,
|
||||
var signName: String? = null,
|
||||
var signTextColor: Color? = null
|
||||
)
|
||||
@ -0,0 +1,20 @@
|
||||
package com.ray650128.model.pojo.arModelDto
|
||||
|
||||
import com.ray650128.model.pojo.arModel.Float3
|
||||
import com.ray650128.model.pojo.arModel.ModelEvent
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ArModelDto(
|
||||
var _id: String? = null,
|
||||
var ownerId: String? = null,
|
||||
var name: String,
|
||||
var position: Float3,
|
||||
var rotation: Float3,
|
||||
var scale: Float3,
|
||||
var modelData: ModelDataDto,
|
||||
var events: ArrayList<ModelEvent>? = null,
|
||||
var childEvents: HashMap<String, ArrayList<ModelEvent>?>? = null,
|
||||
var createAt: Long? = null,
|
||||
var updatedAt: Long? = null
|
||||
)
|
||||
@ -0,0 +1,14 @@
|
||||
package com.ray650128.model.pojo.arModelDto
|
||||
|
||||
import com.ray650128.model.pojo.Material
|
||||
import com.ray650128.model.pojo.arModel.ModelParams
|
||||
import kotlinx.serialization.Contextual
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.litote.kmongo.Id
|
||||
|
||||
@Serializable
|
||||
data class ModelDataDto(
|
||||
var type: Int = -1,
|
||||
var material: Material? = null,
|
||||
var params: ModelParams
|
||||
)
|
||||
167
src/main/kotlin/com/ray650128/plugins/ArMaterialRouting.kt
Normal file
167
src/main/kotlin/com/ray650128/plugins/ArMaterialRouting.kt
Normal file
@ -0,0 +1,167 @@
|
||||
package com.ray650128.plugins
|
||||
|
||||
import com.ray650128.extension.*
|
||||
import com.ray650128.model.ErrorResponse
|
||||
import com.ray650128.model.pojo.Material
|
||||
import com.ray650128.model.pojo.NewMaterial
|
||||
import com.ray650128.model.pojo.User
|
||||
import com.ray650128.service.MaterialService
|
||||
import com.ray650128.service.UserService
|
||||
import io.ktor.http.content.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.auth.*
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.routing.*
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.io.File
|
||||
|
||||
fun Application.configureArMaterialRouting() {
|
||||
|
||||
val userService = UserService()
|
||||
val materialService = MaterialService()
|
||||
|
||||
routing {
|
||||
route("/upload") {
|
||||
get("/{name}") {
|
||||
val fileName = call.parameters["name"] ?: run {
|
||||
call.sendNotFound()
|
||||
return@get
|
||||
}
|
||||
println("[File]filename: $fileName")
|
||||
val file = File("./upload/$fileName")
|
||||
println("[File]file: ${file.absolutePath}")
|
||||
if(!file.exists()) {
|
||||
call.sendNotFound()
|
||||
return@get
|
||||
}
|
||||
call.respondFile(file)
|
||||
}
|
||||
}
|
||||
|
||||
authenticate {
|
||||
route("/api") {
|
||||
route("/v1") {
|
||||
route("/materials") {
|
||||
get {
|
||||
val user = call.authentication.principal<User>() ?: run {
|
||||
call.sendUnauthorized()
|
||||
return@get
|
||||
}
|
||||
val list = materialService.findByOwnerId(user._id.toString())
|
||||
call.sendSuccess(list)
|
||||
}
|
||||
|
||||
post("/upload") {
|
||||
val user = call.authentication.principal<User>() ?: run {
|
||||
call.sendUnauthorized()
|
||||
return@post
|
||||
}
|
||||
var materialId: String? = null
|
||||
// retrieve all multipart data (suspending)
|
||||
val multipart = call.receiveMultipart()
|
||||
var params: NewMaterial? = null
|
||||
multipart.forEachPart { part ->
|
||||
// Check part type
|
||||
when (part) {
|
||||
is PartData.FormItem -> {
|
||||
params = Json.decodeFromString(NewMaterial.serializer(), part.value)
|
||||
println(part.value)
|
||||
}
|
||||
|
||||
is PartData.FileItem -> {
|
||||
// retrieve file name of upload
|
||||
println("File content type: ${part.contentType?.contentType}/${part.contentType?.contentSubtype}")
|
||||
val extensionName = when (part.contentType?.contentSubtype) {
|
||||
"gltf-binary" -> "glb"
|
||||
"gltf+json" -> "gltf"
|
||||
else -> part.contentType?.contentSubtype
|
||||
}
|
||||
val name = "${System.currentTimeMillis()}.$extensionName"
|
||||
val directory = File("./upload/")
|
||||
if (!directory.exists()) {
|
||||
directory.mkdir()
|
||||
}
|
||||
val file = File("${directory.path}/$name")
|
||||
|
||||
// use InputStream from part to save file
|
||||
part.streamProvider().use { its ->
|
||||
// copy the stream to the file with buffering
|
||||
file.outputStream().buffered().use {
|
||||
// note that this is blocking
|
||||
its.copyTo(it)
|
||||
}
|
||||
}
|
||||
|
||||
val tmpMaterial = Material(
|
||||
ownerId = user._id!!,
|
||||
name = if (params == null) {
|
||||
part.originalFileName!!
|
||||
} else {
|
||||
params!!.name
|
||||
},
|
||||
path = "/upload/$name",
|
||||
contentType = "${part.contentType}",
|
||||
createAt = System.currentTimeMillis()
|
||||
)
|
||||
materialId = materialService.create(tmpMaterial).toString()
|
||||
}
|
||||
|
||||
else -> {}
|
||||
}
|
||||
// make sure to dispose of the part after use to prevent leaks
|
||||
part.dispose()
|
||||
}
|
||||
if (materialId != null) {
|
||||
val data = materialService.findById(materialId!!)
|
||||
call.sendSuccess(data)
|
||||
} else {
|
||||
call.sendBadRequest(ErrorResponse("Add material fail."))
|
||||
}
|
||||
}
|
||||
|
||||
put("/{id}") {
|
||||
call.authentication.principal<User>() ?: run {
|
||||
call.sendUnauthorized()
|
||||
return@put
|
||||
}
|
||||
val body = call.receive<Material>()
|
||||
val id = call.parameters["id"].toString()
|
||||
val material = materialService.findById(id) ?: run {
|
||||
call.sendNotFound()
|
||||
return@put
|
||||
}
|
||||
material.apply {
|
||||
name = body.name
|
||||
fileTag = body.fileTag
|
||||
updatedAt = System.currentTimeMillis()
|
||||
}
|
||||
val isSuccess = materialService.updateById(id, material)
|
||||
call.sendSuccess(mapOf("success" to isSuccess))
|
||||
}
|
||||
|
||||
delete("/{id}") {
|
||||
call.authentication.principal<User>() ?: run {
|
||||
call.sendUnauthorized()
|
||||
return@delete
|
||||
}
|
||||
val id = call.parameters["id"].toString()
|
||||
val material = materialService.findById(id) ?: run {
|
||||
call.sendNotFound()
|
||||
return@delete
|
||||
}
|
||||
val filePath = material.path
|
||||
val file = File(".$filePath")
|
||||
println(file.absolutePath)
|
||||
if (file.exists()) {
|
||||
file.delete()
|
||||
}
|
||||
val isSuccess = materialService.deleteById(id)
|
||||
call.sendSuccess(mapOf("success" to isSuccess))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
81
src/main/kotlin/com/ray650128/plugins/ArModelRouting.kt
Normal file
81
src/main/kotlin/com/ray650128/plugins/ArModelRouting.kt
Normal file
@ -0,0 +1,81 @@
|
||||
package com.ray650128.plugins
|
||||
|
||||
import com.ray650128.extension.*
|
||||
import com.ray650128.model.ErrorResponse
|
||||
import com.ray650128.model.pojo.arModel.ArModel
|
||||
import com.ray650128.model.pojo.User
|
||||
import com.ray650128.service.ModelService
|
||||
import com.ray650128.service.UserService
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.auth.*
|
||||
import io.ktor.server.request.*
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
fun Application.configureArModelRouting() {
|
||||
|
||||
val userService = UserService()
|
||||
val modelService = ModelService()
|
||||
|
||||
routing {
|
||||
route("/api") {
|
||||
route("/v1") {
|
||||
authenticate {
|
||||
route("/models") {
|
||||
get {
|
||||
val account = call.authentication.principal<User>()?.account ?: run {
|
||||
call.sendUnauthorized()
|
||||
return@get
|
||||
}
|
||||
val user = userService.findByAccount(account) ?: run {
|
||||
call.sendUnauthorized()
|
||||
return@get
|
||||
}
|
||||
val list = modelService.findByOwnerId(user._id.toString()).map(ArModel::toDto)
|
||||
call.sendSuccess(list)
|
||||
}
|
||||
|
||||
post("/create") {
|
||||
val user = call.authentication.principal<User>() ?: run {
|
||||
call.sendUnauthorized()
|
||||
return@post
|
||||
}
|
||||
val body = call.receive<ArModel>()
|
||||
body.apply {
|
||||
ownerId = user._id
|
||||
createAt = System.currentTimeMillis()
|
||||
}
|
||||
val modelId = modelService.create(body)
|
||||
if (modelId != null) {
|
||||
val data = modelService.findById(modelId.toString())?.toDto()
|
||||
call.sendSuccess(data)
|
||||
} else {
|
||||
call.sendBadRequest(ErrorResponse("Add ar model fail."))
|
||||
}
|
||||
}
|
||||
|
||||
put("/{id}") {
|
||||
call.authentication.principal<User>()?.account ?: run {
|
||||
call.sendUnauthorized()
|
||||
return@put
|
||||
}
|
||||
val body = call.receive<ArModel>()
|
||||
val id = call.parameters["id"].toString()
|
||||
val isSuccess = modelService.updateById(id, body)
|
||||
call.sendSuccess(mapOf("success" to isSuccess))
|
||||
}
|
||||
|
||||
delete("/{id}") {
|
||||
call.authentication.principal<User>()?.account ?: run {
|
||||
call.sendUnauthorized()
|
||||
return@delete
|
||||
}
|
||||
val id = call.parameters["id"].toString()
|
||||
val isSuccess = modelService.deleteById(id)
|
||||
call.sendSuccess(mapOf("success" to isSuccess))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package com.ray650128.plugins
|
||||
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import io.ktor.server.plugins.contentnegotiation.*
|
||||
import io.ktor.server.response.*
|
||||
import io.ktor.server.application.*
|
||||
import io.ktor.server.routing.*
|
||||
|
||||
fun Application.configureSerialization() {
|
||||
install(ContentNegotiation) {
|
||||
json()
|
||||
}
|
||||
routing {
|
||||
get("/json/kotlinx-serialization") {
|
||||
call.respond(mapOf("hello" to "world"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,10 @@
|
||||
package com.ray650128.plugins
|
||||
|
||||
import com.ray650128.JwtConfig
|
||||
import com.ray650128.dto.UserDto
|
||||
import com.ray650128.extension.toDto
|
||||
import com.ray650128.extension.toUser
|
||||
import com.ray650128.extension.*
|
||||
import com.ray650128.model.ErrorResponse
|
||||
import com.ray650128.model.LoginResult
|
||||
import com.ray650128.model.User
|
||||
import com.ray650128.model.pojo.LoginResult
|
||||
import com.ray650128.model.pojo.User
|
||||
import com.ray650128.service.UserService
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.routing.*
|
||||
@ -15,32 +13,31 @@ import io.ktor.server.application.*
|
||||
import io.ktor.server.auth.*
|
||||
import io.ktor.server.request.*
|
||||
|
||||
fun Application.configureRouting() {
|
||||
fun Application.configureUserRouting() {
|
||||
val service = UserService()
|
||||
|
||||
routing {
|
||||
get("/") {
|
||||
call.respondText("Hello World!")
|
||||
}
|
||||
|
||||
route("/api") {
|
||||
route("/v1") {
|
||||
post("/register") {
|
||||
val request = call.receive<UserDto>()
|
||||
val request = call.receive<User>()
|
||||
if (service.findByAccount(request.account) != null) {
|
||||
call.sendBadRequest(ErrorResponse("User has existed."))
|
||||
return@post
|
||||
}
|
||||
val newToken = JwtConfig.generateToken(request)
|
||||
val user = request.toUser().apply {
|
||||
val user = request.apply {
|
||||
token = newToken
|
||||
createAt = System.currentTimeMillis()
|
||||
}
|
||||
service.create(user)
|
||||
?.let { userId ->
|
||||
call.response.headers.append("My-User-Id-Header", userId.toString())
|
||||
call.respond(HttpStatusCode.Created, LoginResult(request.account, newToken))
|
||||
} ?: call.respond(HttpStatusCode.BadRequest, ErrorResponse.BAD_REQUEST_RESPONSE)
|
||||
service.create(user)?.let { userId ->
|
||||
call.response.headers.append("My-User-Id-Header", userId.toString())
|
||||
call.sendCreated(LoginResult(request.account, newToken))
|
||||
} ?: call.sendBadRequest(ErrorResponse.BAD_REQUEST_RESPONSE)
|
||||
}
|
||||
|
||||
post("/login") {
|
||||
val request = call.receive<UserDto>()
|
||||
val request = call.receive<User>()
|
||||
val user = service.findByLoginInfo(request.account, request.password)
|
||||
if (user != null) {
|
||||
var token = user.token
|
||||
@ -48,66 +45,56 @@ fun Application.configureRouting() {
|
||||
token = JwtConfig.generateToken(request)
|
||||
user.token = token
|
||||
user.updatedAt = System.currentTimeMillis()
|
||||
service.updateById(user.id.toString(), user)
|
||||
service.updateById(user._id.toString(), user)
|
||||
}
|
||||
call.respond(HttpStatusCode.OK, LoginResult(request.account, token!!))
|
||||
call.sendSuccess(LoginResult(request.account, token!!))
|
||||
} else {
|
||||
call.respond(
|
||||
status = HttpStatusCode.Unauthorized,
|
||||
message = mapOf("message" to "Account or Password wrong.")
|
||||
)
|
||||
call.sendBadRequest(ErrorResponse("Account or Password wrong."))
|
||||
}
|
||||
}
|
||||
|
||||
authenticate {
|
||||
post("/logout") {
|
||||
val account = call.authentication.principal<UserDto>()?.account ?: run {
|
||||
call.respond(
|
||||
status = HttpStatusCode.Unauthorized,
|
||||
message = mapOf("message" to "token wrong")
|
||||
)
|
||||
val account = call.authentication.principal<User>()?.account ?: run {
|
||||
call.sendUnauthorized()
|
||||
return@post
|
||||
}
|
||||
val user = service.findByAccount(account) ?: run {
|
||||
call.respond(
|
||||
status = HttpStatusCode.Unauthorized,
|
||||
message = mapOf("message" to "token wrong")
|
||||
)
|
||||
call.sendUnauthorized()
|
||||
return@post
|
||||
}
|
||||
user.apply {
|
||||
token = null
|
||||
updatedAt = System.currentTimeMillis()
|
||||
}
|
||||
service.updateById(user.id.toString(), user)
|
||||
call.respond(HttpStatusCode.OK, "User has logged out")
|
||||
service.updateById(user._id.toString(), user)
|
||||
call.sendSuccess(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get {
|
||||
val peopleList = service.findAll().map(User::toDto)
|
||||
val peopleList = service.findAll()
|
||||
call.respond(peopleList)
|
||||
}
|
||||
|
||||
get("/{id}") {
|
||||
val id = call.parameters["id"].toString()
|
||||
service.findById(id)
|
||||
?.let { foundPerson -> call.respond(foundPerson.toDto()) }
|
||||
?: call.respond(HttpStatusCode.NotFound, ErrorResponse.NOT_FOUND_RESPONSE)
|
||||
?.let { foundPerson -> call.respond(foundPerson) }
|
||||
?: call.sendNotFound()
|
||||
}
|
||||
|
||||
get("/search") {
|
||||
val name = call.request.queryParameters["name"].toString()
|
||||
val foundPeople = service.findByName(name).map(User::toDto)
|
||||
val foundPeople = service.findByName(name)
|
||||
call.respond(foundPeople)
|
||||
}
|
||||
|
||||
put("/{id}") {
|
||||
val id = call.parameters["id"].toString()
|
||||
val userRequest = call.receive<UserDto>()
|
||||
val user = userRequest.toUser()
|
||||
val updatedSuccessfully = service.updateById(id, user)
|
||||
val userRequest = call.receive<User>()
|
||||
val updatedSuccessfully = service.updateById(id, userRequest)
|
||||
if (updatedSuccessfully) {
|
||||
call.respond(HttpStatusCode.NoContent)
|
||||
} else {
|
||||
44
src/main/kotlin/com/ray650128/service/MaterialService.kt
Normal file
44
src/main/kotlin/com/ray650128/service/MaterialService.kt
Normal file
@ -0,0 +1,44 @@
|
||||
package com.ray650128.service
|
||||
|
||||
import com.ray650128.model.pojo.Material
|
||||
import com.ray650128.model.pojo.User
|
||||
import org.bson.types.ObjectId
|
||||
import org.litote.kmongo.*
|
||||
import org.litote.kmongo.id.toId
|
||||
|
||||
class MaterialService {
|
||||
private val client = KMongo.createClient("mongodb://www.ray650128.com:27017")
|
||||
private val database = client.getDatabase("ar_system")
|
||||
private val materialCollection = database.getCollection<Material>()
|
||||
|
||||
fun create(material: Material): Id<Material> {
|
||||
materialCollection.insertOne(material)
|
||||
return material._id
|
||||
}
|
||||
|
||||
fun findById(id: String): Material? {
|
||||
val bsonId: Id<Material> = ObjectId(id).toId()
|
||||
return materialCollection.findOne(Material::_id eq bsonId)
|
||||
}
|
||||
|
||||
fun findByOwnerId(ownerId: String): List<Material> {
|
||||
val bsonId: Id<User> = ObjectId(ownerId).toId()
|
||||
return materialCollection.find(Material::ownerId eq bsonId).toList()
|
||||
}
|
||||
|
||||
fun updateById(id: String, request: Material): Boolean =
|
||||
findById(id)?.let { material ->
|
||||
val updateResult = materialCollection.replaceOne(
|
||||
material.copy(
|
||||
name = request.name,
|
||||
updatedAt = request.updatedAt
|
||||
)
|
||||
)
|
||||
updateResult.modifiedCount == 1L
|
||||
} ?: false
|
||||
|
||||
fun deleteById(id: String): Boolean {
|
||||
val deleteResult = materialCollection.deleteOneById(ObjectId(id))
|
||||
return deleteResult.deletedCount == 1L
|
||||
}
|
||||
}
|
||||
50
src/main/kotlin/com/ray650128/service/ModelService.kt
Normal file
50
src/main/kotlin/com/ray650128/service/ModelService.kt
Normal file
@ -0,0 +1,50 @@
|
||||
package com.ray650128.service
|
||||
|
||||
import com.ray650128.model.pojo.arModel.ArModel
|
||||
import com.ray650128.model.pojo.User
|
||||
import org.bson.types.ObjectId
|
||||
import org.litote.kmongo.*
|
||||
import org.litote.kmongo.id.toId
|
||||
|
||||
class ModelService {
|
||||
private val client = KMongo.createClient("mongodb://www.ray650128.com:27017")
|
||||
private val database = client.getDatabase("ar_system")
|
||||
private val arModelCollection = database.getCollection<ArModel>()
|
||||
|
||||
fun create(arModel: ArModel): Id<ArModel>? {
|
||||
arModelCollection.insertOne(arModel)
|
||||
return arModel._id
|
||||
}
|
||||
|
||||
fun findById(id: String): ArModel? {
|
||||
val bsonId: Id<ArModel> = ObjectId(id).toId()
|
||||
return arModelCollection.findOne(ArModel::_id eq bsonId)
|
||||
}
|
||||
|
||||
fun findByOwnerId(ownerId: String): List<ArModel> {
|
||||
val bsonId: Id<User> = ObjectId(ownerId).toId()
|
||||
return arModelCollection.find(ArModel::ownerId eq bsonId).toList()
|
||||
}
|
||||
|
||||
fun updateById(id: String, request: ArModel): Boolean =
|
||||
findById(id)?.let { arModel ->
|
||||
val updateResult = arModelCollection.replaceOne(
|
||||
arModel.copy(
|
||||
name = request.name,
|
||||
position = request.position,
|
||||
rotation = request.rotation,
|
||||
scale = request.scale,
|
||||
modelData = request.modelData,
|
||||
events = request.events,
|
||||
childEvents = request.childEvents,
|
||||
updatedAt = request.updatedAt
|
||||
)
|
||||
)
|
||||
updateResult.modifiedCount == 1L
|
||||
} ?: false
|
||||
|
||||
fun deleteById(id: String): Boolean {
|
||||
val deleteResult = arModelCollection.deleteOneById(ObjectId(id))
|
||||
return deleteResult.deletedCount == 1L
|
||||
}
|
||||
}
|
||||
@ -1,25 +1,25 @@
|
||||
package com.ray650128.service
|
||||
|
||||
import com.ray650128.model.User
|
||||
import com.ray650128.model.pojo.User
|
||||
import org.bson.types.ObjectId
|
||||
import org.litote.kmongo.*
|
||||
import org.litote.kmongo.id.toId
|
||||
|
||||
class UserService {
|
||||
private val client = KMongo.createClient("mongodb://www.ray650128.com:27017")
|
||||
private val database = client.getDatabase("users")
|
||||
private val database = client.getDatabase("ar_system")
|
||||
private val userCollection = database.getCollection<User>()
|
||||
|
||||
fun create(user: User): Id<User>? {
|
||||
userCollection.insertOne(user)
|
||||
return user.id
|
||||
return user._id
|
||||
}
|
||||
|
||||
fun findAll(): List<User> = userCollection.find().toList()
|
||||
|
||||
fun findById(id: String): User? {
|
||||
val bsonId: Id<User> = ObjectId(id).toId()
|
||||
return userCollection.findOne(User::id eq bsonId)
|
||||
return userCollection.findOne(User::_id eq bsonId)
|
||||
}
|
||||
|
||||
fun findByName(name: String): List<User> {
|
||||
|
||||
@ -11,7 +11,7 @@ class ApplicationTest {
|
||||
@Test
|
||||
fun testRoot() = testApplication {
|
||||
application {
|
||||
configureRouting()
|
||||
configureUserRouting()
|
||||
}
|
||||
client.get("/").apply {
|
||||
assertEquals(HttpStatusCode.OK, status)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user