diff options
71 files changed, 2260 insertions, 1227 deletions
diff --git a/README.md b/README.md index a281aa3f..87f90055 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ This repository contains: ## [Ressources](https://docs.fosscord.com/resources/) -- [Contributing](https://docs.fosscord.com/contributing/) +- [Contributing](https://docs.fosscord.com/contributing/server/) ## [Download](https://github.com/fosscord/fosscord-server/releases) diff --git a/api/assets/schemas.json b/api/assets/schemas.json index e27087a9..cc45ebb3 100644 --- a/api/assets/schemas.json +++ b/api/assets/schemas.json @@ -38,7 +38,6 @@ "additionalProperties": false, "required": [ "consent", - "password", "username" ], "$schema": "http://json-schema.org/draft-07/schema#" @@ -80,11 +79,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -141,27 +159,7 @@ } }, "additionalProperties": false, - "required": [ - "name", - "type" - ], "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -307,11 +305,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -367,20 +384,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -469,22 +473,6 @@ }, "additionalProperties": false, "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -630,11 +618,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -690,20 +697,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -741,22 +735,6 @@ }, "additionalProperties": false, "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -902,11 +880,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -962,20 +959,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -992,22 +976,6 @@ }, "additionalProperties": false, "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -1153,11 +1121,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -1213,20 +1200,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -1246,22 +1220,6 @@ "messages" ], "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -1407,11 +1365,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -1467,20 +1444,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -1509,22 +1473,6 @@ "type" ], "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -1670,11 +1618,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -1730,20 +1697,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -1765,22 +1719,6 @@ "name" ], "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -1926,11 +1864,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -1986,20 +1943,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -2016,22 +1960,6 @@ }, "additionalProperties": false, "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -2177,11 +2105,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -2237,20 +2184,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -2279,22 +2213,6 @@ ] }, "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -2440,11 +2358,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -2500,20 +2437,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -2555,22 +2479,6 @@ "name" ], "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -2716,11 +2624,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -2776,20 +2703,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -2870,22 +2784,6 @@ "name" ], "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -3031,11 +2929,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -3091,20 +3008,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -3121,22 +3025,6 @@ }, "additionalProperties": false, "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -3282,11 +3170,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -3342,20 +3249,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -3372,22 +3266,6 @@ "nick" ], "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -3533,11 +3411,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -3593,20 +3490,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -3635,22 +3519,6 @@ }, "additionalProperties": false, "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -3796,11 +3664,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -3856,20 +3743,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -3893,22 +3767,6 @@ ] }, "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -4054,11 +3912,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -4114,20 +3991,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -4147,22 +4011,6 @@ "name" ], "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -4308,11 +4156,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -4368,20 +4235,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -4401,22 +4255,6 @@ "name" ], "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -4562,11 +4400,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -4622,20 +4479,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -4651,22 +4495,6 @@ }, "additionalProperties": false, "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -4812,11 +4640,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -4872,20 +4719,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -4921,22 +4755,6 @@ "channel_id" ], "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -5082,11 +4900,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -5142,20 +4979,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -5198,22 +5022,6 @@ }, "additionalProperties": false, "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -5359,11 +5167,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -5419,20 +5246,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -5453,22 +5267,6 @@ "enabled" ], "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -5614,11 +5412,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -5674,20 +5491,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -5710,22 +5514,6 @@ "name" ], "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -5871,11 +5659,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -5931,20 +5738,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -5967,22 +5761,6 @@ "recipients" ], "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -6128,11 +5906,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -6188,20 +5985,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -6245,22 +6029,6 @@ }, "additionalProperties": false, "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -6406,11 +6174,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -6466,20 +6253,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -6488,30 +6262,17 @@ "type": "object", "properties": { "type": { - "$ref": "#/definitions/RelationshipType" - } - }, - "additionalProperties": false, - "required": [ - "type" - ], - "definitions": { - "ChannelType": { "enum": [ - 0, 1, - 10, - 11, - 12, - 13, 2, 3, - 4, - 5, - 6 + 4 ], "type": "number" - }, + } + }, + "additionalProperties": false, + "definitions": { "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -6657,11 +6418,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -6717,20 +6497,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -6751,22 +6518,6 @@ "username" ], "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -6912,11 +6663,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -6972,20 +6742,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" @@ -7189,22 +6946,6 @@ "timezone_offset" ], "definitions": { - "ChannelType": { - "enum": [ - 0, - 1, - 10, - 11, - 12, - 13, - 2, - 3, - 4, - 5, - 6 - ], - "type": "number" - }, "ChannelPermissionOverwriteType": { "enum": [ 0, @@ -7350,11 +7091,30 @@ "type": "string" }, "type": { - "$ref": "#/definitions/ChannelType" + "enum": [ + 0, + 1, + 10, + 11, + 12, + 13, + 2, + 3, + 4, + 5, + 6 + ], + "type": "number" }, "topic": { "type": "string" }, + "icon": { + "type": [ + "null", + "string" + ] + }, "bitrate": { "type": "integer" }, @@ -7410,20 +7170,7 @@ "type": "integer" } }, - "additionalProperties": false, - "required": [ - "name", - "type" - ] - }, - "RelationshipType": { - "enum": [ - 1, - 2, - 3, - 4 - ], - "type": "number" + "additionalProperties": false } }, "$schema": "http://json-schema.org/draft-07/schema#" diff --git a/api/client_test/index.html b/api/client_test/index.html index ac66df06..ebe92e4c 100644 --- a/api/client_test/index.html +++ b/api/client_test/index.html @@ -19,7 +19,7 @@ ASSET_ENDPOINT: "", MEDIA_PROXY_ENDPOINT: "https://media.discordapp.net", WIDGET_ENDPOINT: `//${location.host}/widget`, - INVITE_HOST: `${location.hostname}`, + INVITE_HOST: `${location.host}/invite`, GUILD_TEMPLATE_HOST: "discord.new", GIFT_CODE_HOST: "discord.gift", RELEASE_CHANNEL: "stable", @@ -45,9 +45,9 @@ `{"trace":false,"canary":false,"logGatewayEvents":true,"logOverlayEvents":true,"logAnalyticsEvents":true,"sourceMapsEnabled":false,"axeEnabled":false}` ); </script> - <script src="/assets/1dfc47a02b92fa11de87.js"></script> - <script src="/assets/60611ef20efa1f11238a.js"></script> - <script src="/assets/b83bc9f9c08cf5073adf.js"></script> - <script src="/assets/e92920082b09191a5bb0.js"></script> + <script src="/assets/479a2f1e7d625dc134b9.js"></script> + <script src="/assets/a15fd133a1d2d77a2424.js"></script> + <script src="/assets/97e6fa22aa08ee4daa5e.js"></script> + <script src="/assets/9b2b7f0632acd0c5e781.js"></script> </body> </html> diff --git a/api/package-lock.json b/api/package-lock.json index 3e8f655d..dcbb75d1 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -11,6 +11,7 @@ "license": "ISC", "dependencies": { "@fosscord/util": "file:../util", + "@types/morgan": "^1.9.3", "ajv": "8.6.2", "ajv-formats": "^2.1.1", "amqplib": "^0.8.0", @@ -34,6 +35,7 @@ "mongoose": "^5.12.3", "mongoose-autopopulate": "^0.12.3", "mongoose-long": "^0.3.2", + "morgan": "^1.10.0", "multer": "^1.4.2", "node-fetch": "^2.6.1", "patch-package": "^6.4.7", @@ -1771,10 +1773,19 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/runtime": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz", - "integrity": "sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw==", + "node_modules/@types/morgan": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.3.tgz", + "integrity": "sha512-BiLcfVqGBZCyNCnCH3F4o2GmDLrpy0HeBVnNlyZG4fo88ZiE9SoiBe3C+2ezuwbjlEyT+PDZ17//TAlRxAn75Q==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/multer": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", + "integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==", + "dev": true, "dependencies": { "regenerator-runtime": "^0.13.4" }, @@ -2550,11 +2561,46 @@ "@types/istanbul-lib-report": "*" } }, - "node_modules/@types/jest": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.1.tgz", - "integrity": "sha512-HTLpVXHrY69556ozYkcq47TtQJXpcWAWfkoqz+ZGz2JnmZhzlRjprCIyFnetSy8gpDWwTTGBcRVv1J1I1vBrHw==", - "dev": true, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/bcrypt": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz", + "integrity": "sha512-9BTgmrhZM2t1bNuDtrtIMVSmmxZBrJ71n8Wg+YgdjHuIWYF7SjjmCPZFB+/5i/o/PIeRpwVJR3P+NrpIItUjqw==", + "hasInstallScript": true, "dependencies": { "jest-diff": "^27.0.0", "pretty-format": "^27.0.0" @@ -7838,11 +7884,52 @@ } } }, - "node_modules/jest-cli/node_modules/jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true, + "node_modules/morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/morgan/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/morgan/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/morgan/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/morphdom": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.6.1.tgz", + "integrity": "sha512-Y8YRbAEP3eKykroIBWrjcfMw7mmwJfjhqdpSvoqinu8Y702nAwikpXcNFDiIkyvfCLxLM9Wu95RZqo4a9jFBaA==", + "dev": true + }, + "node_modules/mpath": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.4.tgz", + "integrity": "sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g==", "engines": { "node": ">= 10.14.2" } @@ -8396,10 +8483,29 @@ "node": ">= 10" } }, - "node_modules/jest-runtime": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", - "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-net-listen": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/on-net-listen/-/on-net-listen-1.1.2.tgz", + "integrity": "sha512-y1HRYy8s/RlcBvDUwKXSmkODMdx4KSuIvloCnQYJ2LdBBC1asY4HtfhXwe3UWknLakATZDnbzht2Ijw3M1EqFg==", "dev": true, "dependencies": { "@jest/console": "^26.6.2", @@ -16786,6 +16892,14 @@ } } }, + "@types/morgan": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.3.tgz", + "integrity": "sha512-BiLcfVqGBZCyNCnCH3F4o2GmDLrpy0HeBVnNlyZG4fo88ZiE9SoiBe3C+2ezuwbjlEyT+PDZ17//TAlRxAn75Q==", + "requires": { + "@types/node": "*" + } + }, "@types/multer": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", @@ -17686,6 +17800,21 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, + "basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, "bcrypt": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz", @@ -22563,6 +22692,38 @@ "integrity": "sha512-5gTjPH6HUmtNhamv8MPwExWo01Z4d9CT5njZlupqqbmxzMXTbDOgCuP/jnK+9SV0Fs7nuyYlXv7pJ/nA2pAAuA==", "requires": {} }, + "morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "requires": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "morphdom": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.6.1.tgz", @@ -23045,6 +23206,11 @@ "ee-first": "1.1.1" } }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, "on-net-listen": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/on-net-listen/-/on-net-listen-1.1.2.tgz", diff --git a/api/package.json b/api/package.json index c54dc0e9..ce5bcdf9 100644 --- a/api/package.json +++ b/api/package.json @@ -70,6 +70,7 @@ }, "dependencies": { "@fosscord/util": "file:../util", + "@types/morgan": "^1.9.3", "ajv": "8.6.2", "ajv-formats": "^2.1.1", "amqplib": "^0.8.0", @@ -93,6 +94,7 @@ "mongoose": "^5.12.3", "mongoose-autopopulate": "^0.12.3", "mongoose-long": "^0.3.2", + "morgan": "^1.10.0", "multer": "^1.4.2", "node-fetch": "^2.6.1", "patch-package": "^6.4.7", diff --git a/api/src/Server.ts b/api/src/Server.ts index b9ca3fba..4a226d12 100644 --- a/api/src/Server.ts +++ b/api/src/Server.ts @@ -1,3 +1,4 @@ +import { OptionsJson } from 'body-parser'; import "missing-native-js-functions"; import { Connection } from "mongoose"; import { Server, ServerOptions } from "lambert-server"; @@ -11,6 +12,7 @@ import path from "path"; import { initRateLimits } from "./middlewares/RateLimit"; import TestClient from "./middlewares/TestClient"; import { initTranslation } from "./middlewares/Translation"; +import morgan from "morgan"; export interface FosscordServerOptions extends ServerOptions {} @@ -36,6 +38,29 @@ export class FosscordServer extends Server { await Config.init(); await initEvent(); + + /* + DOCUMENTATION: uses LOG_REQUESTS environment variable + + # only log 200 and 204 + LOG_REQUESTS=200 204 + # log everything except 200 and 204 + LOG_REQUESTS=-200 204 + # log all requests + LOG_REQUESTS=- + */ + + let logRequests = process.env["LOG_REQUESTS"] != undefined; + if(logRequests) { + this.app.use(morgan("combined", { + skip: (req, res) => { + var skip = !(process.env["LOG_REQUESTS"]?.includes(res.statusCode.toString()) ?? false); + if(process.env["LOG_REQUESTS"]?.charAt(0) == '-') skip = !skip; + return skip; + } + })); + } + this.app.use(CORS); this.app.use(BodyParser({ inflate: true, limit: "10mb" })); @@ -65,6 +90,9 @@ export class FosscordServer extends Server { this.app.use(ErrorHandler); TestClient(this.app); + if(logRequests){ + console.log("Warning: Request logging is enabled! This will spam your console!\nTo disable this, unset the 'LOG_REQUESTS' environment variable!"); + } return super.start(); } } diff --git a/api/src/middlewares/TestClient.ts b/api/src/middlewares/TestClient.ts index 73e7b9c2..79f8f442 100644 --- a/api/src/middlewares/TestClient.ts +++ b/api/src/middlewares/TestClient.ts @@ -67,6 +67,8 @@ export default function TestClient(app: Application) { res.set("Cache-Control", "public, max-age=" + 60 * 60 * 24); res.set("content-type", "text/html"); + if (req.url.startsWith("/invite")) return res.send(html.replace("9b2b7f0632acd0c5e781", "9f24f709a3de09b67c49")); + res.send(html); }); } diff --git a/api/src/routes/auth/register.ts b/api/src/routes/auth/register.ts index efe91625..4d3f2860 100644 --- a/api/src/routes/auth/register.ts +++ b/api/src/routes/auth/register.ts @@ -1,5 +1,5 @@ import { Request, Response, Router } from "express"; -import { trimSpecial, User, Snowflake, Config, defaultSettings } from "@fosscord/util"; +import { trimSpecial, User, Snowflake, Config, defaultSettings, Member, Invite } from "@fosscord/util"; import bcrypt from "bcrypt"; import { EMAIL_REGEX, FieldErrors, route } from "@fosscord/api"; import "missing-native-js-functions"; @@ -19,7 +19,7 @@ export interface RegisterSchema { * @minLength 1 * @maxLength 72 */ - password: string; // TODO: use password strength of config + password?: string; consent: boolean; /** * @TJS-format email @@ -60,7 +60,6 @@ router.post("/", route({ body: "RegisterSchema" }), async (req: Request, res: Re } console.log("register", req.body.email, req.body.username, ip); - // TODO: automatically join invite // TODO: gift_code_sku_id? // TODO: check password strength @@ -87,13 +86,6 @@ router.post("/", route({ body: "RegisterSchema" }), async (req: Request, res: Re }); } - // require invite to register -> e.g. for organizations to send invites to their employees - if (register.requireInvite && !invite) { - throw FieldErrors({ - email: { code: "INVITE_ONLY", message: req.t("auth:register.INVITE_ONLY") } - }); - } - if (email) { // replace all dots and chars after +, if its a gmail.com email if (!email) throw FieldErrors({ email: { code: "INVALID_EMAIL", message: req.t("auth:register.INVALID_EMAIL") } }); @@ -109,13 +101,13 @@ router.post("/", route({ body: "RegisterSchema" }), async (req: Request, res: Re } }); } - } else if (register.email.necessary) { + } else if (register.email.required) { throw FieldErrors({ email: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED") } }); } - if (register.dateOfBirth.necessary && !date_of_birth) { + if (register.dateOfBirth.required && !date_of_birth) { throw FieldErrors({ date_of_birth: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED") } }); @@ -162,8 +154,14 @@ router.post("/", route({ body: "RegisterSchema" }), async (req: Request, res: Re // TODO: check captcha } - // the salt is saved in the password refer to bcrypt docs - password = await bcrypt.hash(password, 12); + if (password) { + // the salt is saved in the password refer to bcrypt docs + password = await bcrypt.hash(password, 12); + } else if (register.password.required) { + throw FieldErrors({ + password: { code: "BASE_TYPE_REQUIRED", message: req.t("common:field.BASE_TYPE_REQUIRED") } + }); + } let exists; // randomly generates a discriminator between 1 and 9999 and checks max five times if it already exists @@ -202,7 +200,7 @@ router.post("/", route({ body: "RegisterSchema" }), async (req: Request, res: Re premium_type: 2, bio: "", mfa_enabled: false, - verified: false, + verified: true, disabled: false, deleted: false, email: email, @@ -217,6 +215,16 @@ router.post("/", route({ body: "RegisterSchema" }), async (req: Request, res: Re fingerprints: [] }).save(); + if (invite) { + // await to fail if the invite doesn't exist (necessary for requireInvite to work properly) (username only signups are possible) + await Invite.joinGuild(user.id, invite); + } else if (register.requireInvite) { + // require invite to register -> e.g. for organizations to send invites to their employees + throw FieldErrors({ + email: { code: "INVITE_ONLY", message: req.t("auth:register.INVITE_ONLY") } + }); + } + return res.json({ token: await generateToken(user.id) }); }); diff --git a/api/src/routes/channels/#channel_id/index.ts b/api/src/routes/channels/#channel_id/index.ts index 02ac9884..61c851e8 100644 --- a/api/src/routes/channels/#channel_id/index.ts +++ b/api/src/routes/channels/#channel_id/index.ts @@ -1,6 +1,16 @@ -import { ChannelDeleteEvent, Channel, ChannelUpdateEvent, emitEvent, ChannelType, ChannelPermissionOverwriteType } from "@fosscord/util"; -import { Router, Response, Request } from "express"; +import { + Channel, + ChannelDeleteEvent, + ChannelPermissionOverwriteType, + ChannelType, + ChannelUpdateEvent, + emitEvent, + Recipient, + handleFile +} from "@fosscord/util"; +import { Request, Response, Router } from "express"; import { route } from "@fosscord/api"; + const router: Router = Router(); // TODO: delete channel // TODO: Get channel @@ -16,23 +26,35 @@ router.get("/", route({ permission: "VIEW_CHANNEL" }), async (req: Request, res: router.delete("/", route({ permission: "MANAGE_CHANNELS" }), async (req: Request, res: Response) => { const { channel_id } = req.params; - const channel = await Channel.findOneOrFail({ id: channel_id }); - - // TODO: Dm channel "close" not delete - const data = channel; + const channel = await Channel.findOneOrFail({ where: { id: channel_id }, relations: ["recipients"] }); - await Promise.all([emitEvent({ event: "CHANNEL_DELETE", data, channel_id } as ChannelDeleteEvent), Channel.delete({ id: channel_id })]); + if (channel.type === ChannelType.DM) { + const recipient = await Recipient.findOneOrFail({ where: { channel_id: channel_id, user_id: req.user_id } }); + recipient.closed = true; + await Promise.all([ + recipient.save(), + emitEvent({ event: "CHANNEL_DELETE", data: channel, user_id: req.user_id } as ChannelDeleteEvent) + ]); + } else if (channel.type === ChannelType.GROUP_DM) { + await Channel.removeRecipientFromChannel(channel, req.user_id); + } else { + await Promise.all([ + Channel.delete({ id: channel_id }), + emitEvent({ event: "CHANNEL_DELETE", data: channel, channel_id } as ChannelDeleteEvent) + ]); + } - res.send(data); + res.send(channel); }); export interface ChannelModifySchema { /** * @maxLength 100 */ - name: string; - type: ChannelType; + name?: string; + type?: ChannelType; topic?: string; + icon?: string | null; bitrate?: number; user_limit?: number; rate_limit_per_user?: number; @@ -53,6 +75,7 @@ export interface ChannelModifySchema { router.patch("/", route({ body: "ChannelModifySchema", permission: "MANAGE_CHANNELS" }), async (req: Request, res: Response) => { var payload = req.body as ChannelModifySchema; const { channel_id } = req.params; + if (payload.icon) payload.icon = await handleFile(`/channel-icons/${channel_id}`, payload.icon); const channel = await Channel.findOneOrFail({ id: channel_id }); channel.assign(payload); diff --git a/api/src/routes/channels/#channel_id/messages/#message_id/ack.ts b/api/src/routes/channels/#channel_id/messages/#message_id/ack.ts index 97d1d19e..786e4581 100644 --- a/api/src/routes/channels/#channel_id/messages/#message_id/ack.ts +++ b/api/src/routes/channels/#channel_id/messages/#message_id/ack.ts @@ -26,7 +26,7 @@ router.post("/", route({ body: "MessageAcknowledgeSchema" }), async (req: Reques data: { channel_id, message_id, - version: 496 + version: 3763 } } as MessageAckEvent); diff --git a/api/src/routes/channels/#channel_id/messages/#message_id/index.ts b/api/src/routes/channels/#channel_id/messages/#message_id/index.ts index b5220fab..7f7de264 100644 --- a/api/src/routes/channels/#channel_id/messages/#message_id/index.ts +++ b/api/src/routes/channels/#channel_id/messages/#message_id/index.ts @@ -3,7 +3,6 @@ import { Router, Response, Request } from "express"; import { route } from "@fosscord/api"; import { handleMessage, postHandleMessage } from "@fosscord/api"; import { MessageCreateSchema } from "../index"; -import { deleteMessageAttachments } from "@fosscord/api/util/Attachments"; const router = Router(); // TODO: message content/embed string length limit @@ -34,7 +33,6 @@ router.patch("/", route({ body: "MessageCreateSchema", permission: "SEND_MESSAGE }); await Promise.all([ - await deleteMessageAttachments(message_id, new_message.attachments), //This delete all the attachments not in the array new_message!.save(), await emitEvent({ event: "MESSAGE_UPDATE", @@ -60,7 +58,6 @@ router.delete("/", route({}), async (req: Request, res: Response) => { permission.hasThrow("MANAGE_MESSAGES"); } - await deleteMessageAttachments(message_id); await Message.delete({ id: message_id }); await emitEvent({ diff --git a/api/src/routes/channels/#channel_id/messages/index.ts b/api/src/routes/channels/#channel_id/messages/index.ts index ec93649e..fab20977 100644 --- a/api/src/routes/channels/#channel_id/messages/index.ts +++ b/api/src/routes/channels/#channel_id/messages/index.ts @@ -1,10 +1,19 @@ import { Router, Response, Request } from "express"; -import { Attachment, Channel, ChannelType, Embed, getPermission, Message } from "@fosscord/util"; +import { + Attachment, + Channel, + ChannelType, + DmChannelDTO, + Embed, + emitEvent, + getPermission, + Message, + MessageCreateEvent, + uploadFile +} from "@fosscord/util"; import { HTTPError } from "lambert-server"; -import { route } from "@fosscord/api"; +import { handleMessage, postHandleMessage, route } from "@fosscord/api"; import multer from "multer"; -import { sendMessage } from "@fosscord/api"; -import { uploadFile } from "@fosscord/api"; import { FindManyOptions, LessThan, MoreThan } from "typeorm"; const router: Router = Router(); @@ -62,9 +71,9 @@ router.get("/", async (req: Request, res: Response) => { if (!channel) throw new HTTPError("Channel not found", 404); isTextChannel(channel.type); - const around = `${req.query.around}`; - const before = `${req.query.before}`; - const after = `${req.query.after}`; + const around = req.query.around ? `${req.query.around}` : undefined; + const before = req.query.before ? `${req.query.before}` : undefined; + const after = req.query.after ? `${req.query.after}` : undefined; const limit = Number(req.query.limit) || 50; if (limit < 1 || limit > 100) throw new HTTPError("limit must be between 1 and 100"); @@ -151,10 +160,11 @@ router.post( return res.status(400).json(error); } } + const channel = await Channel.findOneOrFail({ where: { id: channel_id }, relations: ["recipients", "recipients.user"] }); const embeds = []; if (body.embed) embeds.push(body.embed); - const data = await sendMessage({ + let message = await handleMessage({ ...body, type: 0, pinned: false, @@ -162,9 +172,41 @@ router.post( embeds, channel_id, attachments, - edited_timestamp: undefined + edited_timestamp: undefined, + timestamp: new Date() }); - return res.json(data); + message = await message.save(); + + await channel.assign({ last_message_id: message.id }).save(); + + if (channel.isDm()) { + const channel_dto = await DmChannelDTO.from(channel); + + for (let recipient of channel.recipients!) { + if (recipient.closed) { + await emitEvent({ + event: "CHANNEL_CREATE", + data: channel_dto.excludedRecipients([recipient.user_id]), + user_id: recipient.user_id + }); + } + } + + //Only one recipients should be closed here, since in group DMs the recipient is deleted not closed + await Promise.all( + channel + .recipients!.filter((r) => r.closed) + .map(async (r) => { + r.closed = false; + return await r.save(); + }) + ); + } + + await emitEvent({ event: "MESSAGE_CREATE", channel_id: channel_id, data: message } as MessageCreateEvent); + postHandleMessage(message).catch((e) => {}); // no await as it shouldnt block the message send function and silently catch error + + return res.json(message); } ); diff --git a/api/src/routes/channels/#channel_id/recipients.ts b/api/src/routes/channels/#channel_id/recipients.ts index ea6bc563..c7beeee8 100644 --- a/api/src/routes/channels/#channel_id/recipients.ts +++ b/api/src/routes/channels/#channel_id/recipients.ts @@ -1,5 +1,57 @@ -import { Router, Response, Request } from "express"; +import { Request, Response, Router } from "express"; +import { Channel, ChannelRecipientAddEvent, ChannelType, DiscordApiErrors, DmChannelDTO, emitEvent, PublicUserProjection, Recipient, User } from "@fosscord/util"; + const router: Router = Router(); -// TODO: + +router.put("/:user_id", async (req: Request, res: Response) => { + const { channel_id, user_id } = req.params; + const channel = await Channel.findOneOrFail({ where: { id: channel_id }, relations: ["recipients"] }); + + if (channel.type !== ChannelType.GROUP_DM) { + const recipients = [ + ...channel.recipients!.map(r => r.user_id), + user_id + ].unique() + + const new_channel = await Channel.createDMChannel(recipients, req.user_id) + return res.status(201).json(new_channel); + } else { + if (channel.recipients!.map(r => r.user_id).includes(user_id)) { + throw DiscordApiErrors.INVALID_RECIPIENT //TODO is this the right error? + } + + channel.recipients!.push(new Recipient({ channel_id: channel_id, user_id: user_id })); + await channel.save() + + await emitEvent({ + event: "CHANNEL_CREATE", + data: await DmChannelDTO.from(channel, [user_id]), + user_id: user_id + }); + + await emitEvent({ + event: "CHANNEL_RECIPIENT_ADD", data: { + channel_id: channel_id, + user: await User.findOneOrFail({ where: { id: user_id }, select: PublicUserProjection }) + }, channel_id: channel_id + } as ChannelRecipientAddEvent); + return res.sendStatus(204); + } +}); + +router.delete("/:user_id", async (req: Request, res: Response) => { + const { channel_id, user_id } = req.params; + const channel = await Channel.findOneOrFail({ where: { id: channel_id }, relations: ["recipients"] }); + if (!(channel.type === ChannelType.GROUP_DM && (channel.owner_id === req.user_id || user_id === req.user_id))) + throw DiscordApiErrors.MISSING_PERMISSIONS + + if (!channel.recipients!.map(r => r.user_id).includes(user_id)) { + throw DiscordApiErrors.INVALID_RECIPIENT //TODO is this the right error? + } + + await Channel.removeRecipientFromChannel(channel, user_id) + + return res.sendStatus(204); +}); export default router; diff --git a/api/src/routes/guilds/#guild_id/delete.ts b/api/src/routes/guilds/#guild_id/delete.ts index 7c3c5530..bd158c56 100644 --- a/api/src/routes/guilds/#guild_id/delete.ts +++ b/api/src/routes/guilds/#guild_id/delete.ts @@ -13,15 +13,8 @@ router.post("/", route({}), async (req: Request, res: Response) => { const guild = await Guild.findOneOrFail({ where: { id: guild_id }, select: ["owner_id"] }); if (guild.owner_id !== req.user_id) throw new HTTPError("You are not the owner of this guild", 401); - // do not put everything into promise all, because of "QueryFailedError: SQLITE_CONSTRAINT: FOREIGN KEY constraint failed" - - await Message.delete({ guild_id }); // messages must be deleted before channel - await Promise.all([ - Role.delete({ guild_id }), - Channel.delete({ guild_id }), - Emoji.delete({ guild_id }), - Member.delete({ guild_id }), + Guild.delete({ id: guild_id }), // this will also delete all guild related data emitEvent({ event: "GUILD_DELETE", data: { @@ -31,9 +24,6 @@ router.post("/", route({}), async (req: Request, res: Response) => { } as GuildDeleteEvent) ]); - await Invite.delete({ guild_id }); // invite must be deleted after channel - await Guild.delete({ id: guild_id }); // guild must be deleted after everything else - return res.sendStatus(204); }); diff --git a/api/src/routes/guilds/#guild_id/index.ts b/api/src/routes/guilds/#guild_id/index.ts index 63000b84..d8ee86ff 100644 --- a/api/src/routes/guilds/#guild_id/index.ts +++ b/api/src/routes/guilds/#guild_id/index.ts @@ -1,8 +1,7 @@ import { Request, Response, Router } from "express"; -import { emitEvent, getPermission, Guild, GuildUpdateEvent, Member } from "@fosscord/util"; +import { emitEvent, getPermission, Guild, GuildUpdateEvent, handleFile, Member } from "@fosscord/util"; import { HTTPError } from "lambert-server"; import { route } from "@fosscord/api"; -import { handleFile } from "@fosscord/api"; import "missing-native-js-functions"; import { GuildCreateSchema } from "../index"; diff --git a/api/src/routes/guilds/index.ts b/api/src/routes/guilds/index.ts index 2e68d953..abde147d 100644 --- a/api/src/routes/guilds/index.ts +++ b/api/src/routes/guilds/index.ts @@ -1,7 +1,6 @@ import { Router, Request, Response } from "express"; -import { Role, Guild, Snowflake, Config, User, Member, Channel } from "@fosscord/util"; +import { Role, Guild, Snowflake, Config, Member, Channel, DiscordApiErrors, handleFile } from "@fosscord/util"; import { route } from "@fosscord/api"; -import { DiscordApiErrors } from "@fosscord/util"; import { ChannelModifySchema } from "../channels/#channel_id"; const router: Router = Router(); @@ -34,6 +33,7 @@ router.post("/", route({ body: "GuildCreateSchema" }), async (req: Request, res: await Guild.insert({ name: body.name, + icon: await handleFile(`/icons/${guild_id}`, body.icon as string), region: Config.get().regions.default, owner_id: req.user_id, afk_timeout: 300, diff --git a/api/src/routes/invites/index.ts b/api/src/routes/invites/index.ts index ae8a5944..0fcf7c86 100644 --- a/api/src/routes/invites/index.ts +++ b/api/src/routes/invites/index.ts @@ -15,14 +15,9 @@ router.get("/:code", route({}), async (req: Request, res: Response) => { router.post("/:code", route({}), async (req: Request, res: Response) => { const { code } = req.params; + const invite = await Invite.joinGuild(req.user_id, code); - const invite = await Invite.findOneOrFail({ code }); - if (invite.uses++ >= invite.max_uses) await Invite.delete({ code }); - else await invite.save(); - - await Member.addToGuild(req.user_id, invite.guild_id); - - res.status(200).send(invite); + res.json(invite); }); // * cant use permission of route() function because path doesn't have guild_id/channel_id diff --git a/api/src/routes/sticker-packs/#id/index.ts b/api/src/routes/sticker-packs/#id/index.ts new file mode 100644 index 00000000..2344a48f --- /dev/null +++ b/api/src/routes/sticker-packs/#id/index.ts @@ -0,0 +1,18 @@ +import { Request, Response, Router } from "express"; + +const router: Router = Router(); + +router.get("/", async (req: Request, res: Response) => { + //TODO + res.json({ + id: "", + stickers: [], + name: "", + sku_id: "", + cover_sticker_id: "", + description: "", + banner_asset_id: "" + }).status(200); +}); + +export default router; \ No newline at end of file diff --git a/api/src/routes/sticker-packs/index.ts b/api/src/routes/sticker-packs/index.ts new file mode 100644 index 00000000..6c4e46d8 --- /dev/null +++ b/api/src/routes/sticker-packs/index.ts @@ -0,0 +1,10 @@ +import { Request, Response, Router } from "express"; + +const router: Router = Router(); + +router.get("/", async (req: Request, res: Response) => { + //TODO + res.json({ sticker_packs: [] }).status(200); +}); + +export default router; \ No newline at end of file diff --git a/api/src/routes/users/#id/profile.ts b/api/src/routes/users/#id/profile.ts index d099bce7..15457547 100644 --- a/api/src/routes/users/#id/profile.ts +++ b/api/src/routes/users/#id/profile.ts @@ -19,6 +19,7 @@ router.get("/", route({ test: { response: { body: "UserProfileResponse" } } }), connected_accounts: user.connected_accounts, premium_guild_since: null, // TODO premium_since: null, // TODO + mutual_guilds: [], // TODO {id: "", nick: null} when ?with_mutual_guilds=true user: { username: user.username, discriminator: user.discriminator, diff --git a/api/src/routes/users/@me/channels.ts b/api/src/routes/users/@me/channels.ts index da33f204..b5782eca 100644 --- a/api/src/routes/users/@me/channels.ts +++ b/api/src/routes/users/@me/channels.ts @@ -1,15 +1,12 @@ -import { Router, Request, Response } from "express"; -import { Channel, ChannelCreateEvent, ChannelType, Snowflake, trimSpecial, User, emitEvent, Recipient } from "@fosscord/util"; -import { HTTPError } from "lambert-server"; +import { Request, Response, Router } from "express"; +import { Recipient, DmChannelDTO, Channel } from "@fosscord/util"; import { route } from "@fosscord/api"; -import { In } from "typeorm"; const router: Router = Router(); router.get("/", route({}), async (req: Request, res: Response) => { - const recipients = await Recipient.find({ where: { user_id: req.user_id }, relations: ["channel"] }); - - res.json(recipients.map((x) => x.channel)); + const recipients = await Recipient.find({ where: { user_id: req.user_id, closed: false }, relations: ["channel", "channel.recipients"] }); + res.json(await Promise.all(recipients.map(r => DmChannelDTO.from(r.channel, [req.user_id])))); }); export interface DmChannelCreateSchema { @@ -19,30 +16,7 @@ export interface DmChannelCreateSchema { router.post("/", route({ body: "DmChannelCreateSchema" }), async (req: Request, res: Response) => { const body = req.body as DmChannelCreateSchema; - - body.recipients = body.recipients.filter((x) => x !== req.user_id).unique(); - - const recipients = await User.find({ where: body.recipients.map((x) => ({ id: x })) }); - - if (recipients.length !== body.recipients.length) { - throw new HTTPError("Recipient/s not found"); - } - - const type = body.recipients.length === 1 ? ChannelType.DM : ChannelType.GROUP_DM; - const name = trimSpecial(body.name); - - const channel = await new Channel({ - name, - type, - // owner_id only for group dm channels - created_at: new Date(), - last_message_id: null, - recipients: [...body.recipients.map((x) => new Recipient({ user_id: x })), new Recipient({ user_id: req.user_id })] - }).save(); - - await emitEvent({ event: "CHANNEL_CREATE", data: channel, user_id: req.user_id } as ChannelCreateEvent); - - res.json(channel); + res.json(await Channel.createDMChannel(body.recipients, req.user_id, body.name)); }); export default router; diff --git a/api/src/routes/users/@me/connections.ts b/api/src/routes/users/@me/connections.ts new file mode 100644 index 00000000..411e95bf --- /dev/null +++ b/api/src/routes/users/@me/connections.ts @@ -0,0 +1,11 @@ +import { Request, Response, Router } from "express"; +import { route } from "@fosscord/api"; + +const router: Router = Router(); + +router.get("/", route({}), async (req: Request, res: Response) => { + //TODO + res.json([]).status(200); +}); + +export default router; diff --git a/api/src/routes/users/@me/index.ts b/api/src/routes/users/@me/index.ts index 67b11ce0..f6bb04d7 100644 --- a/api/src/routes/users/@me/index.ts +++ b/api/src/routes/users/@me/index.ts @@ -1,7 +1,6 @@ import { Router, Request, Response } from "express"; -import { User, PrivateUserProjection, emitEvent, UserUpdateEvent } from "@fosscord/util"; +import { User, PrivateUserProjection, emitEvent, UserUpdateEvent, handleFile } from "@fosscord/util"; import { route } from "@fosscord/api"; -import { handleFile } from "@fosscord/api"; const router: Router = Router(); diff --git a/api/src/routes/users/@me/relationships.ts b/api/src/routes/users/@me/relationships.ts index 58d2e481..567c734e 100644 --- a/api/src/routes/users/@me/relationships.ts +++ b/api/src/routes/users/@me/relationships.ts @@ -18,13 +18,23 @@ const router = Router(); const userProjection: (keyof User)[] = ["relationships", ...PublicUserProjection]; router.get("/", route({}), async (req: Request, res: Response) => { - const user = await User.findOneOrFail({ where: { id: req.user_id }, relations: ["relationships"] }); + const user = await User.findOneOrFail({ where: { id: req.user_id }, relations: ["relationships", "relationships.to"] }); + + //TODO DTO + const related_users = user.relationships.map((r) => { + return { + id: r.to.id, + type: r.type, + nickname: null, + user: r.to.toPublicUser() + }; + }); - return res.json(user.relationships); + return res.json(related_users); }); export interface RelationshipPutSchema { - type: RelationshipType; + type?: RelationshipType; } router.put("/:id", route({ body: "RelationshipPutSchema" }), async (req: Request, res: Response) => { @@ -32,7 +42,7 @@ router.put("/:id", route({ body: "RelationshipPutSchema" }), async (req: Request req, res, await User.findOneOrFail({ id: req.params.id }, { relations: ["relationships", "relationships.to"], select: userProjection }), - req.body.type + req.body.type ?? RelationshipType.friends ); }); @@ -48,7 +58,10 @@ router.post("/", route({ body: "RelationshipPostSchema" }), async (req: Request, await User.findOneOrFail({ relations: ["relationships", "relationships.to"], select: userProjection, - where: req.body as { discriminator: string; username: string } + where: { + discriminator: String(req.body.discriminator).padStart(4, "0"), //Discord send the discriminator as integer, we need to add leading zeroes + username: req.body.username + } }), req.body.type ); diff --git a/api/src/util/Attachments.ts b/api/src/util/Attachments.ts deleted file mode 100644 index addda97f..00000000 --- a/api/src/util/Attachments.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Attachment } from "@fosscord/util"; -import { deleteFile } from "@fosscord/api"; -import { URL } from "url"; - -export async function deleteMessageAttachments(messageId: string, keep?: Attachment[]) { - let attachments = await Attachment.find({ message_id: messageId }); - if (keep) - attachments = attachments.filter(x => !keep.map(k => k.id).includes(x.id)); - await Promise.all(attachments.map(a => a.remove())); - - attachments.forEach(a => deleteFile((new URL(a.url)).pathname)); //We don't need to await since this is done on the cdn -} diff --git a/api/src/util/cdn.ts b/api/src/util/cdn.ts index 88b0ea0d..8c6e9ac9 100644 --- a/api/src/util/cdn.ts +++ b/api/src/util/cdn.ts @@ -42,9 +42,9 @@ export async function handleFile(path: string, body?: string): Promise<string | export async function deleteFile(path: string) { const response = await fetch(`${Config.get().cdn.endpoint || "http://localhost:3003"}${path}`, { headers: { - signature: Config.get().security.requestSignature, + signature: Config.get().security.requestSignature }, - method: "DELETE", + method: "DELETE" }); const result = await response.json(); diff --git a/api/src/util/index.ts b/api/src/util/index.ts index 4b1e8e77..3e47ce4e 100644 --- a/api/src/util/index.ts +++ b/api/src/util/index.ts @@ -1,5 +1,4 @@ export * from "./Base64"; -export * from "./cdn"; export * from "./FieldError"; export * from "./ipAddress"; export * from "./Message"; diff --git a/api/src/util/route.ts b/api/src/util/route.ts index 9ef92c3a..5b06a2b5 100644 --- a/api/src/util/route.ts +++ b/api/src/util/route.ts @@ -14,6 +14,7 @@ export const ajv = new Ajv({ parseDate: true, allowDate: true, schemas, + coerceTypes: true, messages: true, strict: true, strictRequired: true diff --git a/bundle/.vscode/launch.json b/bundle/.vscode/launch.json index 0b5d2287..917f2a93 100644 --- a/bundle/.vscode/launch.json +++ b/bundle/.vscode/launch.json @@ -10,9 +10,11 @@ "request": "launch", "name": "Launch server bundle", "program": "${workspaceFolder}/dist/start.js", + "runtimeArgs": ["-r", "./tsconfig-paths-bootstrap.js"], "preLaunchTask": "tsc: build - tsconfig.json", - "outFiles": ["${workspaceFolder}/dist/**/*.js"], - "envFile": "${workspaceFolder}/.env" + "outFiles": ["${workspaceFolder}/dist/**/*.js", "${workspaceFolder}/node_modules/@fosscord/**/*.js"], + "envFile": "${workspaceFolder}/.env", + "outDir": "${workspaceFolder}/dist" } ] } diff --git a/bundle/package-lock.json b/bundle/package-lock.json index 08e09450..6a658842 100644 --- a/bundle/package-lock.json +++ b/bundle/package-lock.json @@ -37,7 +37,7 @@ "@types/uuid": "^8.3.0", "@types/ws": "^7.4.0", "@zerollup/ts-transform-paths": "^1.7.18", - "ts-patch": "^1.4.4", + "ts-node": "^10.2.1", "typescript": "^4.3.5" } }, @@ -48,6 +48,7 @@ "license": "ISC", "dependencies": { "@fosscord/util": "file:../util", + "@types/morgan": "^1.9.3", "ajv": "8.6.2", "ajv-formats": "^2.1.1", "amqplib": "^0.8.0", @@ -71,6 +72,7 @@ "mongoose": "^5.12.3", "mongoose-autopopulate": "^0.12.3", "mongoose-long": "^0.3.2", + "morgan": "^1.10.0", "multer": "^1.4.2", "node-fetch": "^2.6.1", "patch-package": "^6.4.7", @@ -227,6 +229,27 @@ "node": ">=6.9.0" } }, + "node_modules/@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz", + "integrity": "sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-consumer": "0.8.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@fosscord/api": { "resolved": "../api", "link": true @@ -243,6 +266,30 @@ "resolved": "../util", "link": true }, + "node_modules/@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "dev": true + }, "node_modules/@types/amqplib": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/@types/amqplib/-/amqplib-0.8.2.tgz", @@ -497,30 +544,33 @@ "node": ">= 0.6" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/acorn": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", "dev": true, + "bin": { + "acorn": "bin/acorn" + }, "engines": { - "node": ">=8" + "node": ">=0.4.0" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=0.4.0" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -724,6 +774,12 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -754,6 +810,15 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -1056,14 +1121,11 @@ "json5": "lib/cli.js" } }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true }, "node_modules/media-typer": { "version": "0.3.0", @@ -1399,25 +1461,48 @@ "node": ">=0.6" } }, - "node_modules/ts-patch": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/ts-patch/-/ts-patch-1.4.4.tgz", - "integrity": "sha512-b0CxxrkrCGsD22gl5BtSFlXzyTFP2mbOVffxMOWRrwdSh37sM01wzxSY4wlbBiHHHAJICmaaDgESzJ8lKkVoZA==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "glob": "^7.1.7", - "global-prefix": "^3.0.0", - "minimist": "^1.2.5", - "resolve": "^1.20.0", - "shelljs": "^0.8.4", - "strip-ansi": "^6.0.0" + "node_modules/ts-node": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.1.tgz", + "integrity": "sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "0.6.1", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "yn": "3.1.1" }, "bin": { - "ts-patch": "bin/cli.js" + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "engines": { + "node": ">=12.0.0" }, "peerDependencies": { - "typescript": ">2.7.0" + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } } }, "node_modules/tsconfig-paths": { @@ -1480,23 +1565,14 @@ "node": ">= 0.8" } }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" + "engines": { + "node": ">=6" } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true } }, "dependencies": { @@ -1509,6 +1585,21 @@ "regenerator-runtime": "^0.13.4" } }, + "@cspotcode/source-map-consumer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", + "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", + "dev": true + }, + "@cspotcode/source-map-support": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.6.1.tgz", + "integrity": "sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg==", + "dev": true, + "requires": { + "@cspotcode/source-map-consumer": "0.8.0" + } + }, "@fosscord/api": { "version": "file:../api", "requires": { @@ -1523,6 +1614,7 @@ "@types/mongoose": "^5.10.5", "@types/mongoose-autopopulate": "^0.10.1", "@types/mongoose-lean-virtuals": "^0.5.1", + "@types/morgan": "^1.9.3", "@types/multer": "^1.4.5", "@types/node": "^14.17.9", "@types/node-fetch": "^2.5.7", @@ -1554,6 +1646,7 @@ "mongoose": "^5.12.3", "mongoose-autopopulate": "^0.12.3", "mongoose-long": "^0.3.2", + "morgan": "^1.10.0", "multer": "^1.4.2", "node-fetch": "^2.6.1", "patch-package": "^6.4.7", @@ -1665,6 +1758,30 @@ "typescript-json-schema": "^0.50.1" } }, + "@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "dev": true + }, "@types/amqplib": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/@types/amqplib/-/amqplib-0.8.2.tgz", @@ -1909,20 +2026,23 @@ "negotiator": "0.6.2" } }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "acorn": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", "dev": true }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true }, "array-flatten": { "version": "1.1.1", @@ -2066,6 +2186,12 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -2090,6 +2216,12 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -2324,10 +2456,10 @@ "minimist": "^1.2.0" } }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, "media-typer": { @@ -2588,19 +2720,24 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, - "ts-patch": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/ts-patch/-/ts-patch-1.4.4.tgz", - "integrity": "sha512-b0CxxrkrCGsD22gl5BtSFlXzyTFP2mbOVffxMOWRrwdSh37sM01wzxSY4wlbBiHHHAJICmaaDgESzJ8lKkVoZA==", + "ts-node": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.1.tgz", + "integrity": "sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw==", "dev": true, "requires": { - "chalk": "^4.1.0", - "glob": "^7.1.7", - "global-prefix": "^3.0.0", - "minimist": "^1.2.5", - "resolve": "^1.20.0", - "shelljs": "^0.8.4", - "strip-ansi": "^6.0.0" + "@cspotcode/source-map-support": "0.6.1", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "yn": "3.1.1" } }, "tsconfig-paths": { @@ -2644,19 +2781,10 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true } } diff --git a/bundle/package.json b/bundle/package.json index 7cf4ba40..72b24568 100644 --- a/bundle/package.json +++ b/bundle/package.json @@ -44,7 +44,7 @@ "@types/uuid": "^8.3.0", "@types/ws": "^7.4.0", "@zerollup/ts-transform-paths": "^1.7.18", - "ts-patch": "^1.4.4", + "ts-node": "^10.2.1", "typescript": "^4.3.5" }, "dependencies": { diff --git a/bundle/src/start.ts b/bundle/src/start.ts index 843e3812..f68a65bf 100644 --- a/bundle/src/start.ts +++ b/bundle/src/start.ts @@ -13,7 +13,7 @@ if (cluster.isMaster && !process.env.masterStarted) { initStats(); if (cores === 1) { - require("./Server.js"); + require("./Server"); return; } @@ -23,10 +23,12 @@ if (cluster.isMaster && !process.env.masterStarted) { } cluster.on("exit", (worker: any, code: any, signal: any) => { - console.log(`[Worker] died with pid: ${worker.process.pid} , restarting ...`); + console.log( + `[Worker] died with pid: ${worker.process.pid} , restarting ...` + ); cluster.fork(); }); })(); } else { - require("./Server.js"); + require("./Server"); } diff --git a/cdn/src/Server.ts b/cdn/src/Server.ts index 5c4a8ae5..590eda6f 100644 --- a/cdn/src/Server.ts +++ b/cdn/src/Server.ts @@ -58,6 +58,9 @@ export class CDNServer extends Server { this.app.use("/team-icons/", avatarsRoute); this.log("verbose", "[Server] Route /team-icons registered"); + this.app.use("/channel-icons/", avatarsRoute); + this.log("verbose", "[Server] Route /channel-icons registered"); + return super.start(); } diff --git a/gateway/src/listener/listener.ts b/gateway/src/listener/listener.ts index ef3dd890..ae13cca7 100644 --- a/gateway/src/listener/listener.ts +++ b/gateway/src/listener/listener.ts @@ -32,7 +32,7 @@ export async function setupListener(this: WebSocket) { }); const guilds = members.map((x) => x.guild); const recipients = await Recipient.find({ - where: { user_id: this.user_id }, + where: { user_id: this.user_id, closed: false }, relations: ["channel"], }); const dm_channels = recipients.map((x) => x.channel); @@ -116,7 +116,7 @@ async function consume(this: WebSocket, opts: EventOpts) { .has("VIEW_CHANNEL") ) return; - // TODO: check if user has permission to channel + //No break needed here, we need to call the listenEvent function below case "GUILD_CREATE": this.events[id] = await listenEvent(id, consumer, listenOpts); break; diff --git a/gateway/src/opcodes/Identify.ts b/gateway/src/opcodes/Identify.ts index f6a4478f..d91cd7f2 100644 --- a/gateway/src/opcodes/Identify.ts +++ b/gateway/src/opcodes/Identify.ts @@ -88,20 +88,17 @@ export async function onIdentify(this: WebSocket, data: Payload) { const user_guild_settings_entries = members.map((x) => x.settings); const recipients = await Recipient.find({ - where: { user_id: this.user_id }, + where: { user_id: this.user_id, closed: false }, relations: ["channel", "channel.recipients", "channel.recipients.user"], // TODO: public user selection }); const channels = recipients.map((x) => { // @ts-ignore x.channel.recipients = x.channel.recipients?.map((x) => x.user); - // @ts-ignore - users = users.concat(x.channel.recipients); - if (x.channel.type === ChannelType.DM) { - x.channel.recipients = [ - // @ts-ignore - x.channel.recipients.find((x) => x.id !== this.user_id), - ]; + //TODO is this needed? check if users in group dm that are not friends are sent in the READY event + //users = users.concat(x.channel.recipients); + if (x.channel.isDm()) { + x.channel.recipients = x.channel.recipients!.filter((x) => x.id !== this.user_id); } return x.channel; }); @@ -111,16 +108,19 @@ export async function onIdentify(this: WebSocket, data: Payload) { }); if (!user) return this.close(CLOSECODES.Authentication_failed); - const public_user = { - username: user.username, - discriminator: user.discriminator, - id: user.id, - public_flags: user.public_flags, - avatar: user.avatar, - bot: user.bot, - bio: user.bio, - }; - users.push(public_user); + for (let relation of user.relationships) { + const related_user = relation.to + const public_related_user = { + username: related_user.username, + discriminator: related_user.discriminator, + id: related_user.id, + public_flags: related_user.public_flags, + avatar: related_user.avatar, + bot: related_user.bot, + bio: related_user.bio, + }; + users.push(public_related_user); + } const session_id = genSessionId(); this.session_id = session_id; //Set the session of the WebSocket object @@ -201,7 +201,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { // @ts-ignore experiments: experiments, // TODO guild_join_requests: [], // TODO what is this? - users: users.unique(), // TODO + users: users.unique(), merged_members: merged_members, // shard // TODO: only for bots sharding // application // TODO for applications diff --git a/gateway/src/opcodes/index.ts b/gateway/src/opcodes/index.ts index a6d13bfb..c4069589 100644 --- a/gateway/src/opcodes/index.ts +++ b/gateway/src/opcodes/index.ts @@ -21,5 +21,6 @@ export default { 8: onRequestGuildMembers, // 9: Invalid Session // 10: Hello + // 13: Dm_update 14: onLazyRequest, }; diff --git a/util/package-lock.json b/util/package-lock.json index 4b0f1f15..f4129614 100644 --- a/util/package-lock.json +++ b/util/package-lock.json @@ -18,6 +18,7 @@ "jsonwebtoken": "^8.5.1", "lambert-server": "^1.2.10", "missing-native-js-functions": "^1.2.15", + "multer": "^1.4.3", "node-fetch": "^2.6.1", "patch-package": "^6.4.7", "pg": "^8.7.1", @@ -32,6 +33,7 @@ "@types/amqplib": "^0.8.1", "@types/jsonwebtoken": "^8.5.0", "@types/mongoose-autopopulate": "^0.10.1", + "@types/multer": "^1.4.7", "@types/node": "^14.17.9", "@types/node-fetch": "^2.5.12", "jest": "^27.0.6" @@ -224,19 +226,19 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.4.tgz", - "integrity": "sha512-9fHHSGE9zTC++KuXLZcB5FKgvlV83Ox+NLUmQTawovwlJ85+QMhk1CnVk406CQVj97LaWod6KVjl2Sfgw9Aktw==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.7.tgz", + "integrity": "sha512-ZNqjjQG/AuFfekFTY+7nY4RgBSklgTu970c7Rj3m/JOhIu5KPBUuTA9AY6zaKcUvk4g6EbDXdBnhi35FAssdSw==", "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.15.4", "@babel/helper-replace-supers": "^7.15.4", "@babel/helper-simple-access": "^7.15.4", "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-validator-identifier": "^7.15.7", "@babel/template": "^7.15.4", "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/types": "^7.15.6" }, "engines": { "node": ">=6.9.0" @@ -303,9 +305,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", "dev": true, "engines": { "node": ">=6.9.0" @@ -420,9 +422,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.6.tgz", - "integrity": "sha512-S/TSCcsRuCkmpUuoWijua0Snt+f3ewU/8spLo+4AXJCZfT0bVCzLD5MuOKdrx0mlAptbKzn5AdgEIIKXxXkz9Q==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.7.tgz", + "integrity": "sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -1063,6 +1065,48 @@ "integrity": "sha512-HBNx4lhkxN7bx6P0++W8E289foSu8kO8GCk2unhuVggO+cE7rh9DhZUyPhUxNRG9m+5B5BTKxZQ5ZP92x/mx9Q==", "dev": true }, + "node_modules/@types/body-parser": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.1.tgz", + "integrity": "sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz", + "integrity": "sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, "node_modules/@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -1115,6 +1159,12 @@ "@types/node": "*" } }, + "node_modules/@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, "node_modules/@types/mongodb": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-4.0.7.tgz", @@ -1144,10 +1194,19 @@ "@types/mongoose": "5.10.5" } }, + "node_modules/@types/multer": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", + "integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, "node_modules/@types/node": { - "version": "14.17.16", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.16.tgz", - "integrity": "sha512-WiFf2izl01P1CpeY8WqFAeKWwByMueBEkND38EcN8N68qb0aDG3oIS1P5MhAX5kUdr469qRyqsY/MjanLjsFbQ==" + "version": "14.17.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.17.tgz", + "integrity": "sha512-niAjcewgEYvSPCZm3OaM9y6YQrL2SEPH9PymtE6fuZAvFiP6ereCcvApGl2jKTq7copTIguX3PBvfP08LN4LvQ==" }, "node_modules/@types/node-fetch": { "version": "2.5.12", @@ -1165,6 +1224,28 @@ "integrity": "sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog==", "dev": true }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "node_modules/@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, "node_modules/@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", @@ -1396,6 +1477,11 @@ "node": ">= 6.0.0" } }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" + }, "node_modules/aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -1816,6 +1902,18 @@ "node": ">=4" } }, + "node_modules/busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "dependencies": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -1843,9 +1941,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001257", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001257.tgz", - "integrity": "sha512-JN49KplOgHSXpIsVSF+LUyhD8PUp6xPpAXeRrrcBh4KBeP7W864jHn6RvzJgDlrReyeVjMFJL3PLpPvKIxlIHA==", + "version": "1.0.30001258", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001258.tgz", + "integrity": "sha512-RBByOG6xWXUp0CR2/WU2amXz3stjKpSl5J1xU49F1n2OxD//uBZO4wCKUiG+QMGf7CHGfDDcqoKriomoGVxTeA==", "dev": true, "funding": { "type": "opencollective", @@ -2028,6 +2126,52 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -2258,6 +2402,18 @@ "node": ">=8" } }, + "node_modules/dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "dependencies": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + }, + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -2342,9 +2498,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "node_modules/electron-to-chromium": { - "version": "1.3.840", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.840.tgz", - "integrity": "sha512-yRoUmTLDJnkIJx23xLY7GbSvnmDCq++NSuxHDQ0jiyDJ9YZBUGJcrdUqm+ZwZFzMbCciVzfem2N2AWiHJcWlbw==", + "version": "1.3.843", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.843.tgz", + "integrity": "sha512-OWEwAbzaVd1Lk9MohVw8LxMXFlnYd9oYTYxfX8KS++kLLjDfbovLOcEEXwRhG612dqGQ6+44SZvim0GXuBRiKg==", "dev": true }, "node_modules/emittery": { @@ -4619,6 +4775,24 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "node_modules/multer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.3.tgz", + "integrity": "sha512-np0YLKncuZoTzufbkM6wEKp68EhWJXcU6fq6QqrSwkckd2LlMgd1UqhUJLj6NS/5sZ8dE8LYDWslsltJznnXlg==", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^0.2.11", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "on-finished": "^2.3.0", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.10.0" + } + }, "node_modules/mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -6075,13 +6249,12 @@ } }, "node_modules/stack-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.4.tgz", - "integrity": "sha512-ERg+H//lSSYlZhBIUu+wJnqg30AbyBbpZlIhcshpn7BNzpoRODZgfyr9J+8ERf3ooC6af3u7Lcl01nleau7MrA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", "dev": true, "dependencies": { - "escape-string-regexp": "^2.0.0", - "source-map-support": "^0.5.20" + "escape-string-regexp": "^2.0.0" }, "engines": { "node": ">=10" @@ -6095,6 +6268,14 @@ "node": ">= 0.6" } }, + "node_modules/streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", @@ -6448,6 +6629,11 @@ "node": ">= 0.6" } }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -7348,19 +7534,19 @@ } }, "@babel/helper-module-transforms": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.4.tgz", - "integrity": "sha512-9fHHSGE9zTC++KuXLZcB5FKgvlV83Ox+NLUmQTawovwlJ85+QMhk1CnVk406CQVj97LaWod6KVjl2Sfgw9Aktw==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.7.tgz", + "integrity": "sha512-ZNqjjQG/AuFfekFTY+7nY4RgBSklgTu970c7Rj3m/JOhIu5KPBUuTA9AY6zaKcUvk4g6EbDXdBnhi35FAssdSw==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.15.4", "@babel/helper-replace-supers": "^7.15.4", "@babel/helper-simple-access": "^7.15.4", "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-validator-identifier": "^7.15.7", "@babel/template": "^7.15.4", "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/types": "^7.15.6" } }, "@babel/helper-optimise-call-expression": { @@ -7409,9 +7595,9 @@ } }, "@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", "dev": true }, "@babel/helper-validator-option": { @@ -7501,9 +7687,9 @@ } }, "@babel/parser": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.6.tgz", - "integrity": "sha512-S/TSCcsRuCkmpUuoWijua0Snt+f3ewU/8spLo+4AXJCZfT0bVCzLD5MuOKdrx0mlAptbKzn5AdgEIIKXxXkz9Q==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.7.tgz", + "integrity": "sha512-rycZXvQ+xS9QyIcJ9HXeDWf1uxqlbVFAUq0Rq0dbc50Zb/+wUe/ehyfzGfm9KZZF0kBejYgxltBXocP+gKdL2g==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -8011,6 +8197,48 @@ "integrity": "sha512-HBNx4lhkxN7bx6P0++W8E289foSu8kO8GCk2unhuVggO+cE7rh9DhZUyPhUxNRG9m+5B5BTKxZQ5ZP92x/mx9Q==", "dev": true }, + "@types/body-parser": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.1.tgz", + "integrity": "sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz", + "integrity": "sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -8063,6 +8291,12 @@ "@types/node": "*" } }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, "@types/mongodb": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-4.0.7.tgz", @@ -8091,10 +8325,19 @@ "@types/mongoose": "5.10.5" } }, + "@types/multer": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.7.tgz", + "integrity": "sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, "@types/node": { - "version": "14.17.16", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.16.tgz", - "integrity": "sha512-WiFf2izl01P1CpeY8WqFAeKWwByMueBEkND38EcN8N68qb0aDG3oIS1P5MhAX5kUdr469qRyqsY/MjanLjsFbQ==" + "version": "14.17.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.17.tgz", + "integrity": "sha512-niAjcewgEYvSPCZm3OaM9y6YQrL2SEPH9PymtE6fuZAvFiP6ereCcvApGl2jKTq7copTIguX3PBvfP08LN4LvQ==" }, "@types/node-fetch": { "version": "2.5.12", @@ -8112,6 +8355,28 @@ "integrity": "sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog==", "dev": true }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, "@types/stack-utils": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", @@ -8290,6 +8555,11 @@ "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz", "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==" }, + "append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" + }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -8647,6 +8917,15 @@ "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" }, + "busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "requires": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + } + }, "bytes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", @@ -8665,9 +8944,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001257", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001257.tgz", - "integrity": "sha512-JN49KplOgHSXpIsVSF+LUyhD8PUp6xPpAXeRrrcBh4KBeP7W864jHn6RvzJgDlrReyeVjMFJL3PLpPvKIxlIHA==", + "version": "1.0.30001258", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001258.tgz", + "integrity": "sha512-RBByOG6xWXUp0CR2/WU2amXz3stjKpSl5J1xU49F1n2OxD//uBZO4wCKUiG+QMGf7CHGfDDcqoKriomoGVxTeA==", "dev": true }, "caseless": { @@ -8815,6 +9094,51 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -9006,6 +9330,15 @@ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true }, + "dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "requires": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + } + }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -9071,9 +9404,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.3.840", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.840.tgz", - "integrity": "sha512-yRoUmTLDJnkIJx23xLY7GbSvnmDCq++NSuxHDQ0jiyDJ9YZBUGJcrdUqm+ZwZFzMbCciVzfem2N2AWiHJcWlbw==", + "version": "1.3.843", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.843.tgz", + "integrity": "sha512-OWEwAbzaVd1Lk9MohVw8LxMXFlnYd9oYTYxfX8KS++kLLjDfbovLOcEEXwRhG612dqGQ6+44SZvim0GXuBRiKg==", "dev": true }, "emittery": { @@ -10830,6 +11163,21 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "multer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.3.tgz", + "integrity": "sha512-np0YLKncuZoTzufbkM6wEKp68EhWJXcU6fq6QqrSwkckd2LlMgd1UqhUJLj6NS/5sZ8dE8LYDWslsltJznnXlg==", + "requires": { + "append-field": "^1.0.0", + "busboy": "^0.2.11", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "on-finished": "^2.3.0", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + } + }, "mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -11951,13 +12299,12 @@ } }, "stack-utils": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.4.tgz", - "integrity": "sha512-ERg+H//lSSYlZhBIUu+wJnqg30AbyBbpZlIhcshpn7BNzpoRODZgfyr9J+8ERf3ooC6af3u7Lcl01nleau7MrA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", "dev": true, "requires": { - "escape-string-regexp": "^2.0.0", - "source-map-support": "^0.5.20" + "escape-string-regexp": "^2.0.0" } }, "statuses": { @@ -11965,6 +12312,11 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + }, "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", @@ -12237,6 +12589,11 @@ "mime-types": "~2.1.24" } }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, "typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", diff --git a/util/package.json b/util/package.json index 751484af..2fa93f9b 100644 --- a/util/package.json +++ b/util/package.json @@ -31,6 +31,7 @@ "@types/amqplib": "^0.8.1", "@types/jsonwebtoken": "^8.5.0", "@types/mongoose-autopopulate": "^0.10.1", + "@types/multer": "^1.4.7", "@types/node": "^14.17.9", "@types/node-fetch": "^2.5.12", "jest": "^27.0.6" @@ -44,6 +45,7 @@ "jsonwebtoken": "^8.5.1", "lambert-server": "^1.2.10", "missing-native-js-functions": "^1.2.15", + "multer": "^1.4.3", "node-fetch": "^2.6.1", "patch-package": "^6.4.7", "pg": "^8.7.1", diff --git a/util/src/dtos/DmChannelDTO.ts b/util/src/dtos/DmChannelDTO.ts new file mode 100644 index 00000000..8b7a18fd --- /dev/null +++ b/util/src/dtos/DmChannelDTO.ts @@ -0,0 +1,35 @@ +import { MinimalPublicUserDTO } from "./UserDTO"; +import { Channel, PublicUserProjection, User } from "../entities"; + +export class DmChannelDTO { + icon: string | null; + id: string; + last_message_id: string | null; + name: string | null; + origin_channel_id: string | null; + owner_id?: string; + recipients: MinimalPublicUserDTO[]; + type: number; + + static async from(channel: Channel, excluded_recipients: string[] = [], origin_channel_id?: string) { + const obj = new DmChannelDTO() + obj.icon = channel.icon || null + obj.id = channel.id + obj.last_message_id = channel.last_message_id || null + obj.name = channel.name || null + obj.origin_channel_id = origin_channel_id || null + obj.owner_id = channel.owner_id + obj.type = channel.type + obj.recipients = (await Promise.all(channel.recipients!.filter(r => !excluded_recipients.includes(r.user_id)).map(async r => { + return await User.findOneOrFail({ where: { id: r.user_id }, select: PublicUserProjection }) + }))).map(u => new MinimalPublicUserDTO(u)) + return obj + } + + excludedRecipients(excluded_recipients: string[]): DmChannelDTO { + return { + ...this, + recipients: this.recipients.filter(r => !excluded_recipients.includes(r.id)) + } + } +} \ No newline at end of file diff --git a/util/src/dtos/UserDTO.ts b/util/src/dtos/UserDTO.ts new file mode 100644 index 00000000..f09b5f4e --- /dev/null +++ b/util/src/dtos/UserDTO.ts @@ -0,0 +1,17 @@ +import { User } from "../entities"; + +export class MinimalPublicUserDTO { + avatar?: string | null; + discriminator: string; + id: string; + public_flags: number; + username: string; + + constructor(user: User) { + this.avatar = user.avatar + this.discriminator = user.discriminator + this.id = user.id + this.public_flags = user.public_flags + this.username = user.username + } +} \ No newline at end of file diff --git a/util/src/dtos/index.ts b/util/src/dtos/index.ts new file mode 100644 index 00000000..13702342 --- /dev/null +++ b/util/src/dtos/index.ts @@ -0,0 +1,2 @@ +export * from "./DmChannelDTO"; +export * from "./UserDTO"; \ No newline at end of file diff --git a/util/src/entities/Application.ts b/util/src/entities/Application.ts index 2092cd4e..fab3d93f 100644 --- a/util/src/entities/Application.ts +++ b/util/src/entities/Application.ts @@ -41,7 +41,9 @@ export class Application extends BaseClass { verify_key: string; @JoinColumn({ name: "team_id" }) - @ManyToOne(() => Team) + @ManyToOne(() => Team, { + onDelete: "CASCADE", + }) team?: Team; @JoinColumn({ name: "guild_id" }) diff --git a/util/src/entities/Attachment.ts b/util/src/entities/Attachment.ts index ca893400..7b4b17eb 100644 --- a/util/src/entities/Attachment.ts +++ b/util/src/entities/Attachment.ts @@ -1,4 +1,6 @@ -import { Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; +import { BeforeRemove, Column, Entity, JoinColumn, ManyToOne, RelationId } from "typeorm"; +import { URL } from "url"; +import { deleteFile } from "../util/cdn"; import { BaseClass } from "./BaseClass"; @Entity("attachments") @@ -29,6 +31,13 @@ export class Attachment extends BaseClass { message_id: string; @JoinColumn({ name: "message_id" }) - @ManyToOne(() => require("./Message").Message, (message: import("./Message").Message) => message.attachments) + @ManyToOne(() => require("./Message").Message, (message: import("./Message").Message) => message.attachments, { + onDelete: "CASCADE", + }) message: import("./Message").Message; + + @BeforeRemove() + onDelete() { + return deleteFile(new URL(this.url).pathname); + } } diff --git a/util/src/entities/Ban.ts b/util/src/entities/Ban.ts index e8a6d648..9504bd8e 100644 --- a/util/src/entities/Ban.ts +++ b/util/src/entities/Ban.ts @@ -10,7 +10,9 @@ export class Ban extends BaseClass { user_id: string; @JoinColumn({ name: "user_id" }) - @ManyToOne(() => User) + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) user: User; @Column({ nullable: true }) @@ -18,7 +20,9 @@ export class Ban extends BaseClass { guild_id: string; @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild) + @ManyToOne(() => Guild, { + onDelete: "CASCADE", + }) guild: Guild; @Column({ nullable: true }) diff --git a/util/src/entities/BaseClass.ts b/util/src/entities/BaseClass.ts index 9b2ce058..d18757f2 100644 --- a/util/src/entities/BaseClass.ts +++ b/util/src/entities/BaseClass.ts @@ -1,5 +1,15 @@ import "reflect-metadata"; -import { BaseEntity, BeforeInsert, BeforeUpdate, EntityMetadata, FindConditions, PrimaryColumn } from "typeorm"; +import { + BaseEntity, + BeforeInsert, + BeforeUpdate, + EntityMetadata, + FindConditions, + getConnection, + getManager, + PrimaryColumn, + RemoveOptions, +} from "typeorm"; import { Snowflake } from "../util/Snowflake"; import "missing-native-js-functions"; @@ -69,6 +79,42 @@ export class BaseClassWithoutId extends BaseEntity { const repository = this.getRepository(); return repository.decrement(conditions, propertyPath, value); } + + // static async delete<T>(criteria: FindConditions<T>, options?: RemoveOptions) { + // if (!criteria) throw new Error("You need to specify delete criteria"); + + // const repository = this.getRepository(); + // const promises = repository.metadata.relations.map(async (x) => { + // if (x.orphanedRowAction !== "delete") return; + + // const foreignKey = + // x.foreignKeys.find((key) => key.entityMetadata === repository.metadata) || + // x.inverseRelation?.foreignKeys[0]; // find foreign key for this entity + // if (!foreignKey) { + // throw new Error( + // `Foreign key not found for entity ${repository.metadata.name} in relation ${x.propertyName}` + // ); + // } + // const id = (criteria as any)[foreignKey.referencedColumnNames[0]]; + // if (!id) throw new Error("id missing in criteria options " + foreignKey.referencedColumnNames); + + // if (x.relationType === "many-to-many") { + // return getConnection() + // .createQueryBuilder() + // .relation(this, x.propertyName) + // .of(id) + // .remove({ [foreignKey.columnNames[0]]: id }); + // } else if ( + // x.relationType === "one-to-one" || + // x.relationType === "many-to-one" || + // x.relationType === "one-to-many" + // ) { + // return (x.inverseEntityMetadata.target as any).delete({ [foreignKey.columnNames[0]]: id }); + // } + // }); + // await Promise.all(promises); + // return super.delete(criteria, options); + // } } export class BaseClass extends BaseClassWithoutId { diff --git a/util/src/entities/Channel.ts b/util/src/entities/Channel.ts index fc954f63..ece82bd0 100644 --- a/util/src/entities/Channel.ts +++ b/util/src/entities/Channel.ts @@ -1,12 +1,17 @@ -import { Column, Entity, JoinColumn, JoinTable, ManyToMany, ManyToOne, OneToMany, RelationId } from "typeorm"; +import { Column, Entity, JoinColumn, ManyToOne, OneToMany, RelationId } from "typeorm"; import { BaseClass } from "./BaseClass"; import { Guild } from "./Guild"; -import { Message } from "./Message"; -import { User } from "./User"; +import { PublicUserProjection, User } from "./User"; import { HTTPError } from "lambert-server"; -import { emitEvent, getPermission, Snowflake } from "../util"; -import { ChannelCreateEvent } from "../interfaces"; +import { containsAll, emitEvent, getPermission, Snowflake, trimSpecial } from "../util"; +import { ChannelCreateEvent, ChannelRecipientRemoveEvent } from "../interfaces"; import { Recipient } from "./Recipient"; +import { Message } from "./Message"; +import { ReadState } from "./ReadState"; +import { Invite } from "./Invite"; +import { VoiceState } from "./VoiceState"; +import { Webhook } from "./Webhook"; +import { DmChannelDTO } from "../dtos"; export enum ChannelType { GUILD_TEXT = 0, // a text channel within a server @@ -31,26 +36,29 @@ export class Channel extends BaseClass { @Column({ nullable: true }) name?: string; + @Column({ type: "text", nullable: true }) + icon?: string | null; + @Column({ type: "simple-enum", enum: ChannelType }) type: ChannelType; - @OneToMany(() => Recipient, (recipient: Recipient) => recipient.channel, { cascade: true }) + @OneToMany(() => Recipient, (recipient: Recipient) => recipient.channel, { + cascade: true, + orphanedRowAction: "delete", + }) recipients?: Recipient[]; @Column({ nullable: true }) - @RelationId((channel: Channel) => channel.last_message) last_message_id: string; - @JoinColumn({ name: "last_message_id" }) - @ManyToOne(() => Message) - last_message?: Message; - @Column({ nullable: true }) @RelationId((channel: Channel) => channel.guild) guild_id?: string; @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild) + @ManyToOne(() => Guild, { + onDelete: "CASCADE", + }) guild: Guild; @Column({ nullable: true }) @@ -100,6 +108,36 @@ export class Channel extends BaseClass { @Column({ nullable: true }) topic?: string; + @OneToMany(() => Invite, (invite: Invite) => invite.channel, { + cascade: true, + orphanedRowAction: "delete", + }) + invites?: Invite[]; + + @OneToMany(() => Message, (message: Message) => message.channel, { + cascade: true, + orphanedRowAction: "delete", + }) + messages?: Message[]; + + @OneToMany(() => VoiceState, (voice_state: VoiceState) => voice_state.channel, { + cascade: true, + orphanedRowAction: "delete", + }) + voice_states?: VoiceState[]; + + @OneToMany(() => ReadState, (read_state: ReadState) => read_state.channel, { + cascade: true, + orphanedRowAction: "delete", + }) + read_states?: ReadState[]; + + @OneToMany(() => Webhook, (webhook: Webhook) => webhook.channel, { + cascade: true, + orphanedRowAction: "delete", + }) + webhooks?: Webhook[]; + // TODO: DM channel static async createChannel( channel: Partial<Channel>, @@ -162,6 +200,123 @@ export class Channel extends BaseClass { return channel; } + + static async createDMChannel(recipients: string[], creator_user_id: string, name?: string) { + recipients = recipients.unique().filter((x) => x !== creator_user_id); + const otherRecipientsUsers = await User.find({ where: recipients.map((x) => ({ id: x })) }); + + // TODO: check config for max number of recipients + if (otherRecipientsUsers.length !== recipients.length) { + throw new HTTPError("Recipient/s not found"); + } + + const type = recipients.length === 1 ? ChannelType.DM : ChannelType.GROUP_DM; + + let channel = null; + + const channelRecipients = [...recipients, creator_user_id]; + + const userRecipients = await Recipient.find({ + where: { user_id: creator_user_id }, + relations: ["channel", "channel.recipients"], + }); + + for (let ur of userRecipients) { + let re = ur.channel.recipients!.map((r) => r.user_id); + if (re.length === channelRecipients.length) { + if (containsAll(re, channelRecipients)) { + if (channel == null) { + channel = ur.channel; + await ur.assign({ closed: false }).save(); + } + } + } + } + + if (channel == null) { + name = trimSpecial(name); + + channel = await new Channel({ + name, + type, + owner_id: type === ChannelType.DM ? undefined : creator_user_id, + created_at: new Date(), + last_message_id: null, + recipients: channelRecipients.map( + (x) => + new Recipient({ user_id: x, closed: !(type === ChannelType.GROUP_DM || x === creator_user_id) }) + ), + }).save(); + } + + const channel_dto = await DmChannelDTO.from(channel); + + if (type === ChannelType.GROUP_DM) { + for (let recipient of channel.recipients!) { + await emitEvent({ + event: "CHANNEL_CREATE", + data: channel_dto.excludedRecipients([recipient.user_id]), + user_id: recipient.user_id, + }); + } + } else { + await emitEvent({ event: "CHANNEL_CREATE", data: channel_dto, user_id: creator_user_id }); + } + + return channel_dto.excludedRecipients([creator_user_id]); + } + + static async removeRecipientFromChannel(channel: Channel, user_id: string) { + await Recipient.delete({ channel_id: channel.id, user_id: user_id }); + channel.recipients = channel.recipients?.filter((r) => r.user_id !== user_id); + + if (channel.recipients?.length === 0) { + await Channel.deleteChannel(channel); + await emitEvent({ + event: "CHANNEL_DELETE", + data: await DmChannelDTO.from(channel, [user_id]), + user_id: user_id, + }); + return; + } + + await emitEvent({ + event: "CHANNEL_DELETE", + data: await DmChannelDTO.from(channel, [user_id]), + user_id: user_id, + }); + + //If the owner leave we make the first recipient in the list the new owner + if (channel.owner_id === user_id) { + channel.owner_id = channel.recipients!.find((r) => r.user_id !== user_id)!.user_id; //Is there a criteria to choose the new owner? + await emitEvent({ + event: "CHANNEL_UPDATE", + data: await DmChannelDTO.from(channel, [user_id]), + channel_id: channel.id, + }); + } + + await channel.save(); + + await emitEvent({ + event: "CHANNEL_RECIPIENT_REMOVE", + data: { + channel_id: channel.id, + user: await User.findOneOrFail({ where: { id: user_id }, select: PublicUserProjection }), + }, + channel_id: channel.id, + } as ChannelRecipientRemoveEvent); + } + + static async deleteChannel(channel: Channel) { + await Message.delete({ channel_id: channel.id }); //TODO we should also delete the attachments from the cdn but to do that we need to move cdn.ts in util + //TODO before deleting the channel we should check and delete other relations + await Channel.delete({ id: channel.id }); + } + + isDm() { + return this.type === ChannelType.DM || this.type === ChannelType.GROUP_DM; + } } export interface ChannelPermissionOverwrite { diff --git a/util/src/entities/Config.ts b/util/src/entities/Config.ts index fd830db8..f969b6bb 100644 --- a/util/src/entities/Config.ts +++ b/util/src/entities/Config.ts @@ -110,13 +110,13 @@ export interface ConfigValue { }; register: { email: { - necessary: boolean; // we have to use necessary instead of required as the cli tool uses json schema and can't use required + required: boolean; allowlist: boolean; blocklist: boolean; domains: string[]; }; dateOfBirth: { - necessary: boolean; + required: boolean; minimum: number; // in years }; requireCaptcha: boolean; @@ -125,6 +125,7 @@ export interface ConfigValue { allowMultipleAccounts: boolean; blockProxies: boolean; password: { + required: boolean; minLength: number; minNumbers: number; minUpperCase: number; @@ -246,14 +247,14 @@ export const DefaultConfigOptions: ConfigValue = { }, register: { email: { - necessary: true, + required: false, allowlist: false, blocklist: true, domains: [], // TODO: efficiently save domain blocklist in database // domains: fs.readFileSync(__dirname + "/blockedEmailDomains.txt", { encoding: "utf8" }).split("\n"), }, dateOfBirth: { - necessary: true, + required: false, minimum: 13, }, requireInvite: false, @@ -262,6 +263,7 @@ export const DefaultConfigOptions: ConfigValue = { allowMultipleAccounts: true, blockProxies: true, password: { + required: false, minLength: 8, minNumbers: 2, minUpperCase: 2, diff --git a/util/src/entities/ConnectedAccount.ts b/util/src/entities/ConnectedAccount.ts index 59a8f423..b8aa2889 100644 --- a/util/src/entities/ConnectedAccount.ts +++ b/util/src/entities/ConnectedAccount.ts @@ -11,7 +11,9 @@ export class ConnectedAccount extends BaseClass { user_id: string; @JoinColumn({ name: "user_id" }) - @ManyToOne(() => User) + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) user: User; @Column({ select: false }) diff --git a/util/src/entities/Emoji.ts b/util/src/entities/Emoji.ts index 181aff2c..a252d9f4 100644 --- a/util/src/entities/Emoji.ts +++ b/util/src/entities/Emoji.ts @@ -15,7 +15,9 @@ export class Emoji extends BaseClass { guild_id: string; @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild) + @ManyToOne(() => Guild, { + onDelete: "CASCADE", + }) guild: Guild; @Column() diff --git a/util/src/entities/Guild.ts b/util/src/entities/Guild.ts index 7b5d2908..e107937d 100644 --- a/util/src/entities/Guild.ts +++ b/util/src/entities/Guild.ts @@ -81,7 +81,10 @@ export class Guild extends BaseClass { // application?: string; @JoinColumn({ name: "ban_ids" }) - @OneToMany(() => Ban, (ban: Ban) => ban.guild) + @OneToMany(() => Ban, (ban: Ban) => ban.guild, { + cascade: true, + orphanedRowAction: "delete", + }) bans: Ban[]; @Column({ nullable: true }) @@ -124,15 +127,26 @@ export class Guild extends BaseClass { @Column({ nullable: true }) presence_count?: number; // users online - @OneToMany(() => Member, (member: Member) => member.guild) + @OneToMany(() => Member, (member: Member) => member.guild, { + cascade: true, + orphanedRowAction: "delete", + onDelete: "CASCADE", + }) members: Member[]; @JoinColumn({ name: "role_ids" }) - @OneToMany(() => Role, (role: Role) => role.guild) + @OneToMany(() => Role, (role: Role) => role.guild, { + cascade: true, + orphanedRowAction: "delete", + onDelete: "CASCADE", + }) roles: Role[]; @JoinColumn({ name: "channel_ids" }) - @OneToMany(() => Channel, (channel: Channel) => channel.guild) + @OneToMany(() => Channel, (channel: Channel) => channel.guild, { + cascade: true, + orphanedRowAction: "delete", + }) channels: Channel[]; @Column({ nullable: true }) @@ -144,23 +158,43 @@ export class Guild extends BaseClass { template: Template; @JoinColumn({ name: "emoji_ids" }) - @OneToMany(() => Emoji, (emoji: Emoji) => emoji.guild) + @OneToMany(() => Emoji, (emoji: Emoji) => emoji.guild, { + cascade: true, + orphanedRowAction: "delete", + onDelete: "CASCADE", + }) emojis: Emoji[]; @JoinColumn({ name: "sticker_ids" }) - @OneToMany(() => Sticker, (sticker: Sticker) => sticker.guild) + @OneToMany(() => Sticker, (sticker: Sticker) => sticker.guild, { + cascade: true, + orphanedRowAction: "delete", + onDelete: "CASCADE", + }) stickers: Sticker[]; @JoinColumn({ name: "invite_ids" }) - @OneToMany(() => Invite, (invite: Invite) => invite.guild) + @OneToMany(() => Invite, (invite: Invite) => invite.guild, { + cascade: true, + orphanedRowAction: "delete", + onDelete: "CASCADE", + }) invites: Invite[]; @JoinColumn({ name: "voice_state_ids" }) - @OneToMany(() => VoiceState, (voicestate: VoiceState) => voicestate.guild) + @OneToMany(() => VoiceState, (voicestate: VoiceState) => voicestate.guild, { + cascade: true, + orphanedRowAction: "delete", + onDelete: "CASCADE", + }) voice_states: VoiceState[]; @JoinColumn({ name: "webhook_ids" }) - @OneToMany(() => Webhook, (webhook: Webhook) => webhook.guild) + @OneToMany(() => Webhook, (webhook: Webhook) => webhook.guild, { + cascade: true, + orphanedRowAction: "delete", + onDelete: "CASCADE", + }) webhooks: Webhook[]; @Column({ nullable: true }) diff --git a/util/src/entities/Invite.ts b/util/src/entities/Invite.ts index afad9c02..78545b02 100644 --- a/util/src/entities/Invite.ts +++ b/util/src/entities/Invite.ts @@ -1,4 +1,5 @@ import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn, RelationId } from "typeorm"; +import { Member } from "."; import { BaseClass } from "./BaseClass"; import { Channel } from "./Channel"; import { Guild } from "./Guild"; @@ -34,7 +35,9 @@ export class Invite extends BaseClass { guild_id: string; @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild) + @ManyToOne(() => Guild, { + onDelete: "CASCADE", + }) guild: Guild; @Column({ nullable: true }) @@ -42,7 +45,9 @@ export class Invite extends BaseClass { channel_id: string; @JoinColumn({ name: "channel_id" }) - @ManyToOne(() => Channel) + @ManyToOne(() => Channel, { + onDelete: "CASCADE", + }) channel: Channel; @Column({ nullable: true }) @@ -58,9 +63,20 @@ export class Invite extends BaseClass { target_user_id: string; @JoinColumn({ name: "target_user_id" }) - @ManyToOne(() => User) + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) target_user?: string; // could be used for "User specific invites" https://github.com/fosscord/fosscord/issues/62 @Column({ nullable: true }) target_user_type?: number; + + static async joinGuild(user_id: string, code: string) { + const invite = await Invite.findOneOrFail({ code }); + if (invite.uses++ >= invite.max_uses && invite.max_uses !== 0) await Invite.delete({ code }); + else await invite.save(); + + await Member.addToGuild(user_id, invite.guild_id); + return invite; + } } diff --git a/util/src/entities/Member.ts b/util/src/entities/Member.ts index 66f5d9a1..feb9c069 100644 --- a/util/src/entities/Member.ts +++ b/util/src/entities/Member.ts @@ -39,7 +39,9 @@ export class Member extends BaseClassWithoutId { id: string; @JoinColumn({ name: "id" }) - @ManyToOne(() => User) + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) user: User; @Column() @@ -47,7 +49,9 @@ export class Member extends BaseClassWithoutId { guild_id: string; @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild) + @ManyToOne(() => Guild, { + onDelete: "CASCADE", + }) guild: Guild; @Column({ nullable: true }) @@ -55,7 +59,6 @@ export class Member extends BaseClassWithoutId { @JoinTable({ name: "member_roles", - joinColumn: { name: "index", referencedColumnName: "index" }, inverseJoinColumn: { name: "role_id", diff --git a/util/src/entities/Message.ts b/util/src/entities/Message.ts index 506db71a..c4901693 100644 --- a/util/src/entities/Message.ts +++ b/util/src/entities/Message.ts @@ -8,12 +8,14 @@ import { Column, CreateDateColumn, Entity, + FindConditions, JoinColumn, JoinTable, ManyToMany, ManyToOne, OneToMany, RelationId, + RemoveOptions, UpdateDateColumn, } from "typeorm"; import { BaseClass } from "./BaseClass"; @@ -52,7 +54,9 @@ export class Message extends BaseClass { channel_id: string; @JoinColumn({ name: "channel_id" }) - @ManyToOne(() => Channel) + @ManyToOne(() => Channel, { + onDelete: "CASCADE", + }) channel: Channel; @Column({ nullable: true }) @@ -60,7 +64,9 @@ export class Message extends BaseClass { guild_id?: string; @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild) + @ManyToOne(() => Guild, { + onDelete: "CASCADE", + }) guild?: Guild; @Column({ nullable: true }) @@ -68,7 +74,9 @@ export class Message extends BaseClass { author_id: string; @JoinColumn({ name: "author_id", referencedColumnName: "id" }) - @ManyToOne(() => User) + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) author?: User; @Column({ nullable: true }) @@ -112,7 +120,7 @@ export class Message extends BaseClass { mention_everyone?: boolean; @JoinTable({ name: "message_user_mentions" }) - @ManyToMany(() => User) + @ManyToMany(() => User, { orphanedRowAction: "delete", onDelete: "CASCADE", cascade: true }) mentions: User[]; @JoinTable({ name: "message_role_mentions" }) @@ -127,8 +135,10 @@ export class Message extends BaseClass { @ManyToMany(() => Sticker) sticker_items?: Sticker[]; - @JoinColumn({ name: "attachment_ids" }) - @OneToMany(() => Attachment, (attachment: Attachment) => attachment.message, { cascade: true }) + @OneToMany(() => Attachment, (attachment: Attachment) => attachment.message, { + cascade: true, + orphanedRowAction: "delete", + }) attachments?: Attachment[]; @Column({ type: "simple-json" }) diff --git a/util/src/entities/ReadState.ts b/util/src/entities/ReadState.ts index 8dd05b21..68e867a0 100644 --- a/util/src/entities/ReadState.ts +++ b/util/src/entities/ReadState.ts @@ -15,7 +15,9 @@ export class ReadState extends BaseClass { channel_id: string; @JoinColumn({ name: "channel_id" }) - @ManyToOne(() => Channel) + @ManyToOne(() => Channel, { + onDelete: "CASCADE", + }) channel: Channel; @Column({ nullable: true }) @@ -23,7 +25,9 @@ export class ReadState extends BaseClass { user_id: string; @JoinColumn({ name: "user_id" }) - @ManyToOne(() => User) + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) user: User; @Column({ nullable: true }) diff --git a/util/src/entities/Recipient.ts b/util/src/entities/Recipient.ts index 2a27b29f..a945f938 100644 --- a/util/src/entities/Recipient.ts +++ b/util/src/entities/Recipient.ts @@ -8,7 +8,9 @@ export class Recipient extends BaseClass { channel_id: string; @JoinColumn({ name: "channel_id" }) - @ManyToOne(() => require("./Channel").Channel) + @ManyToOne(() => require("./Channel").Channel, { + onDelete: "CASCADE", + }) channel: import("./Channel").Channel; @Column() @@ -16,8 +18,13 @@ export class Recipient extends BaseClass { user_id: string; @JoinColumn({ name: "user_id" }) - @ManyToOne(() => require("./User").User) + @ManyToOne(() => require("./User").User, { + onDelete: "CASCADE", + }) user: import("./User").User; + @Column({ default: false }) + closed: boolean; + // TODO: settings/mute/nick/added at/encryption keys/read_state } diff --git a/util/src/entities/Relationship.ts b/util/src/entities/Relationship.ts index 61b3ac82..e016b36b 100644 --- a/util/src/entities/Relationship.ts +++ b/util/src/entities/Relationship.ts @@ -17,7 +17,9 @@ export class Relationship extends BaseClass { from_id: string; @JoinColumn({ name: "from_id" }) - @ManyToOne(() => User) + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) from: User; @Column({}) @@ -25,7 +27,9 @@ export class Relationship extends BaseClass { to_id: string; @JoinColumn({ name: "to_id" }) - @ManyToOne(() => User) + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) to: User; @Column({ nullable: true }) diff --git a/util/src/entities/Role.ts b/util/src/entities/Role.ts index 33c8d272..9fca99a5 100644 --- a/util/src/entities/Role.ts +++ b/util/src/entities/Role.ts @@ -10,7 +10,9 @@ export class Role extends BaseClass { guild_id: string; @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild) + @ManyToOne(() => Guild, { + onDelete: "CASCADE", + }) guild: Guild; @Column() diff --git a/util/src/entities/Session.ts b/util/src/entities/Session.ts index d42a8f98..7cc325f5 100644 --- a/util/src/entities/Session.ts +++ b/util/src/entities/Session.ts @@ -11,7 +11,9 @@ export class Session extends BaseClass { user_id: string; @JoinColumn({ name: "user_id" }) - @ManyToOne(() => User) + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) user: User; //TODO check, should be 32 char long hex string diff --git a/util/src/entities/Sticker.ts b/util/src/entities/Sticker.ts index 7730a86a..ab224d1d 100644 --- a/util/src/entities/Sticker.ts +++ b/util/src/entities/Sticker.ts @@ -31,7 +31,9 @@ export class Sticker extends BaseClass { guild_id?: string; @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild) + @ManyToOne(() => Guild, { + onDelete: "CASCADE", + }) guild?: Guild; @Column({ type: "simple-enum", enum: StickerType }) diff --git a/util/src/entities/Team.ts b/util/src/entities/Team.ts index beb8bf68..22140b7f 100644 --- a/util/src/entities/Team.ts +++ b/util/src/entities/Team.ts @@ -9,7 +9,9 @@ export class Team extends BaseClass { icon?: string; @JoinColumn({ name: "member_ids" }) - @OneToMany(() => TeamMember, (member: TeamMember) => member.team) + @OneToMany(() => TeamMember, (member: TeamMember) => member.team, { + orphanedRowAction: "delete", + }) members: TeamMember[]; @Column() diff --git a/util/src/entities/TeamMember.ts b/util/src/entities/TeamMember.ts index 6b184d08..bdfdccf0 100644 --- a/util/src/entities/TeamMember.ts +++ b/util/src/entities/TeamMember.ts @@ -20,7 +20,9 @@ export class TeamMember extends BaseClass { team_id: string; @JoinColumn({ name: "team_id" }) - @ManyToOne(() => require("./Team").Team, (team: import("./Team").Team) => team.members) + @ManyToOne(() => require("./Team").Team, (team: import("./Team").Team) => team.members, { + onDelete: "CASCADE", + }) team: import("./Team").Team; @Column({ nullable: true }) @@ -28,6 +30,8 @@ export class TeamMember extends BaseClass { user_id: string; @JoinColumn({ name: "user_id" }) - @ManyToOne(() => User) + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) user: User; } diff --git a/util/src/entities/User.ts b/util/src/entities/User.ts index 736704f8..4c86b2d8 100644 --- a/util/src/entities/User.ts +++ b/util/src/entities/User.ts @@ -124,14 +124,20 @@ export class User extends BaseClass { flags: string; // UserFlags @Column() - public_flags: string; + public_flags: number; @JoinColumn({ name: "relationship_ids" }) - @OneToMany(() => Relationship, (relationship: Relationship) => relationship.from) + @OneToMany(() => Relationship, (relationship: Relationship) => relationship.from, { + cascade: true, + orphanedRowAction: "delete", + }) relationships: Relationship[]; @JoinColumn({ name: "connected_account_ids" }) - @OneToMany(() => ConnectedAccount, (account: ConnectedAccount) => account.user) + @OneToMany(() => ConnectedAccount, (account: ConnectedAccount) => account.user, { + cascade: true, + orphanedRowAction: "delete", + }) connected_accounts: ConnectedAccount[]; @Column({ type: "simple-json", select: false }) diff --git a/util/src/entities/VoiceState.ts b/util/src/entities/VoiceState.ts index 56eb244e..75748a01 100644 --- a/util/src/entities/VoiceState.ts +++ b/util/src/entities/VoiceState.ts @@ -13,7 +13,9 @@ export class VoiceState extends BaseClass { guild_id: string; @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild) + @ManyToOne(() => Guild, { + onDelete: "CASCADE", + }) guild?: Guild; @Column({ nullable: true }) @@ -21,7 +23,9 @@ export class VoiceState extends BaseClass { channel_id: string; @JoinColumn({ name: "channel_id" }) - @ManyToOne(() => Channel) + @ManyToOne(() => Channel, { + onDelete: "CASCADE", + }) channel: Channel; @Column({ nullable: true }) @@ -29,11 +33,15 @@ export class VoiceState extends BaseClass { user_id: string; @JoinColumn({ name: "user_id" }) - @ManyToOne(() => User) + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) user: User; // @JoinColumn([{ name: "user_id", referencedColumnName: "id" },{ name: "guild_id", referencedColumnName: "guild_id" }]) - // @ManyToOne(() => Member) + // @ManyToOne(() => Member, { + // onDelete: "CASCADE", + // }) //TODO find a way to make it work without breaking Guild.voice_states member: Member; diff --git a/util/src/entities/Webhook.ts b/util/src/entities/Webhook.ts index 12ba0d08..8382435f 100644 --- a/util/src/entities/Webhook.ts +++ b/util/src/entities/Webhook.ts @@ -32,7 +32,9 @@ export class Webhook extends BaseClass { guild_id: string; @JoinColumn({ name: "guild_id" }) - @ManyToOne(() => Guild) + @ManyToOne(() => Guild, { + onDelete: "CASCADE", + }) guild: Guild; @Column({ nullable: true }) @@ -40,7 +42,9 @@ export class Webhook extends BaseClass { channel_id: string; @JoinColumn({ name: "channel_id" }) - @ManyToOne(() => Channel) + @ManyToOne(() => Channel, { + onDelete: "CASCADE", + }) channel: Channel; @Column({ nullable: true }) @@ -48,7 +52,9 @@ export class Webhook extends BaseClass { application_id: string; @JoinColumn({ name: "application_id" }) - @ManyToOne(() => Application) + @ManyToOne(() => Application, { + onDelete: "CASCADE", + }) application: Application; @Column({ nullable: true }) @@ -56,7 +62,9 @@ export class Webhook extends BaseClass { user_id: string; @JoinColumn({ name: "user_id" }) - @ManyToOne(() => User) + @ManyToOne(() => User, { + onDelete: "CASCADE", + }) user: User; @Column({ nullable: true }) @@ -64,6 +72,8 @@ export class Webhook extends BaseClass { source_guild_id: string; @JoinColumn({ name: "source_guild_id" }) - @ManyToOne(() => Guild) + @ManyToOne(() => Guild, { + onDelete: "CASCADE", + }) source_guild: Guild; } diff --git a/util/src/index.ts b/util/src/index.ts index f3bd9e9b..fc00d46b 100644 --- a/util/src/index.ts +++ b/util/src/index.ts @@ -4,6 +4,7 @@ import "reflect-metadata"; export * from "./util/index"; export * from "./interfaces/index"; export * from "./entities/index"; +export * from "./dtos/index"; // import Config from "../util/Config"; // import db, { MongooseCache, toObject } from "./util/Database"; diff --git a/util/src/interfaces/Event.ts b/util/src/interfaces/Event.ts index aff50300..03099bbb 100644 --- a/util/src/interfaces/Event.ts +++ b/util/src/interfaces/Event.ts @@ -127,6 +127,22 @@ export interface ChannelPinsUpdateEvent extends Event { }; } +export interface ChannelRecipientAddEvent extends Event { + event: "CHANNEL_RECIPIENT_ADD"; + data: { + channel_id: string; + user: User; + }; +} + +export interface ChannelRecipientRemoveEvent extends Event { + event: "CHANNEL_RECIPIENT_REMOVE"; + data: { + channel_id: string; + user: User; + }; +} + export interface GuildCreateEvent extends Event { event: "GUILD_CREATE"; data: Guild & { @@ -436,6 +452,8 @@ export type EventData = | ChannelUpdateEvent | ChannelDeleteEvent | ChannelPinsUpdateEvent + | ChannelRecipientAddEvent + | ChannelRecipientRemoveEvent | GuildCreateEvent | GuildUpdateEvent | GuildDeleteEvent @@ -482,6 +500,8 @@ export enum EVENTEnum { ChannelUpdate = "CHANNEL_UPDATE", ChannelDelete = "CHANNEL_DELETE", ChannelPinsUpdate = "CHANNEL_PINS_UPDATE", + ChannelRecipientAdd = "CHANNEL_RECIPIENT_ADD", + ChannelRecipientRemove = "CHANNEL_RECIPIENT_REMOVE", GuildCreate = "GUILD_CREATE", GuildUpdate = "GUILD_UPDATE", GuildDelete = "GUILD_DELETE", @@ -525,6 +545,8 @@ export type EVENT = | "CHANNEL_UPDATE" | "CHANNEL_DELETE" | "CHANNEL_PINS_UPDATE" + | "CHANNEL_RECIPIENT_ADD" + | "CHANNEL_RECIPIENT_REMOVE" | "GUILD_CREATE" | "GUILD_UPDATE" | "GUILD_DELETE" diff --git a/util/src/util/Array.ts b/util/src/util/Array.ts new file mode 100644 index 00000000..27f7c961 --- /dev/null +++ b/util/src/util/Array.ts @@ -0,0 +1,3 @@ +export function containsAll(arr: any[], target: any[]) { + return target.every(v => arr.includes(v)); +} \ No newline at end of file diff --git a/util/src/util/Database.ts b/util/src/util/Database.ts index d3844cd9..c22d8abd 100644 --- a/util/src/util/Database.ts +++ b/util/src/util/Database.ts @@ -21,7 +21,7 @@ export function initDatabase() { // entities: Object.values(Models).filter((x) => x.constructor.name !== "Object"), synchronize: true, - logging: false, + logging: true, cache: { duration: 1000 * 3, // cache all find queries for 3 seconds }, diff --git a/util/src/util/Permissions.ts b/util/src/util/Permissions.ts index 9d87253a..44852f1e 100644 --- a/util/src/util/Permissions.ts +++ b/util/src/util/Permissions.ts @@ -92,6 +92,7 @@ export class Permissions extends BitField { } overwriteChannel(overwrites: ChannelPermissionOverwrite[]) { + if (!overwrites) return this if (!this.cache) throw new Error("permission chache not available"); overwrites = overwrites.filter((x) => { if (x.type === 0 && this.cache.roles?.some((r) => r.id === x.id)) return true; diff --git a/util/src/util/cdn.ts b/util/src/util/cdn.ts new file mode 100644 index 00000000..754d6244 --- /dev/null +++ b/util/src/util/cdn.ts @@ -0,0 +1,54 @@ +import FormData from "form-data"; +import { HTTPError } from "lambert-server"; +import fetch from "node-fetch"; +import { Config } from "./Config"; +import multer from "multer"; + +export async function uploadFile(path: string, file: Express.Multer.File) { + const form = new FormData(); + form.append("file", file.buffer, { + contentType: file.mimetype, + filename: file.originalname, + }); + + const response = await fetch(`${Config.get().cdn.endpoint || "http://localhost:3003"}${path}`, { + headers: { + signature: Config.get().security.requestSignature, + ...form.getHeaders(), + }, + method: "POST", + body: form, + }); + const result = await response.json(); + + if (response.status !== 200) throw result; + return result; +} + +export async function handleFile(path: string, body?: string): Promise<string | undefined> { + if (!body || !body.startsWith("data:")) return body; + try { + const mimetype = body.split(":")[1].split(";")[0]; + const buffer = Buffer.from(body.split(",")[1], "base64"); + + // @ts-ignore + const { id } = await uploadFile(path, { buffer, mimetype, originalname: "banner" }); + return id; + } catch (error) { + console.error(error); + throw new HTTPError("Invalid " + path); + } +} + +export async function deleteFile(path: string) { + const response = await fetch(`${Config.get().cdn.endpoint || "http://localhost:3003"}${path}`, { + headers: { + signature: Config.get().security.requestSignature, + }, + method: "DELETE", + }); + const result = await response.json(); + + if (response.status !== 200) throw result; + return result; +} diff --git a/util/src/util/index.ts b/util/src/util/index.ts index 4e92f017..3160380f 100644 --- a/util/src/util/index.ts +++ b/util/src/util/index.ts @@ -1,6 +1,7 @@ export * from "./ApiError"; export * from "./BitField"; export * from "./checkToken"; +export * from "./cdn"; export * from "./Config"; export * from "./Constants"; export * from "./Database"; @@ -12,3 +13,4 @@ export * from "./RabbitMQ"; export * from "./Regex"; export * from "./Snowflake"; export * from "./String"; +export * from "./Array"; |