diff --git a/server/README.md b/server/README.md index 43f4175..1d09bd3 100644 --- a/server/README.md +++ b/server/README.md @@ -25,6 +25,6 @@ - (?) ack/read deliveries && return ack-count (? or not, how to query?) - - (?) full-text-search: https://www.sqlite.org/fts5.html#contentless_tables + - (?) "login" on website and list/search/filter messages - - (?) "login" on website and list/search/filter messages \ No newline at end of file + - (?) make channels deleteable (soft-delete) (what do with messages in channel?) \ No newline at end of file diff --git a/server/api/handler/api.go b/server/api/handler/api.go index d4588fa..afb23d1 100644 --- a/server/api/handler/api.go +++ b/server/api/handler/api.go @@ -514,7 +514,7 @@ func (h APIHandler) ListChannels(g *gin.Context) ginresp.HTTPResponse { UserID models.UserID `uri:"uid"` } type query struct { - Selector *string `json:"selector" form:"selector"` + Selector *string `json:"selector" form:"selector" enums:"owned,subscribed_any,all_any,subscribed,all"` } type response struct { Channels []models.ChannelJSON `json:"channels"` diff --git a/server/swagger/swagger.json b/server/swagger/swagger.json index af0993e..c4a6f6e 100644 --- a/server/swagger/swagger.json +++ b/server/swagger/swagger.json @@ -1208,6 +1208,64 @@ } } }, + "/api/users/{uid}/channels/": { + "post": { + "tags": [ + "API-v2" + ], + "summary": "Create a new (empty) channel", + "operationId": "api-channels-create", + "parameters": [ + { + "type": "integer", + "description": "UserID", + "name": "uid", + "in": "path", + "required": true + }, + { + "description": " ", + "name": "post_body", + "in": "body", + "schema": { + "$ref": "#/definitions/handler.CreateChannel.body" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.ChannelJSON" + } + }, + "400": { + "description": "supplied values/parameters cannot be parsed / are invalid", + "schema": { + "$ref": "#/definitions/ginresp.apiError" + } + }, + "401": { + "description": "user is not authorized / has missing permissions", + "schema": { + "$ref": "#/definitions/ginresp.apiError" + } + }, + "409": { + "description": "channel already exists", + "schema": { + "$ref": "#/definitions/ginresp.apiError" + } + }, + "500": { + "description": "internal server error", + "schema": { + "$ref": "#/definitions/ginresp.apiError" + } + } + } + } + }, "/api/users/{uid}/channels/{cid}": { "get": { "tags": [ @@ -2317,6 +2375,14 @@ } } }, + "handler.CreateChannel.body": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + }, "handler.CreateSubscription.body": { "type": "object", "required": [ @@ -2906,11 +2972,14 @@ "messages_sent": { "type": "integer" }, - "quota_used": { + "quota_max": { "type": "integer" }, - "quota_used_day": { - "type": "string" + "quota_remaining": { + "type": "integer" + }, + "quota_used": { + "type": "integer" }, "read_key": { "type": "string" @@ -2956,11 +3025,14 @@ "messages_sent": { "type": "integer" }, - "quota_used": { + "quota_max": { "type": "integer" }, - "quota_used_day": { - "type": "string" + "quota_remaining": { + "type": "integer" + }, + "quota_used": { + "type": "integer" }, "read_key": { "type": "string" diff --git a/server/swagger/swagger.yaml b/server/swagger/swagger.yaml index 61c01cf..1697a0d 100644 --- a/server/swagger/swagger.yaml +++ b/server/swagger/swagger.yaml @@ -51,6 +51,11 @@ definitions: - client_type - fcm_token type: object + handler.CreateChannel.body: + properties: + name: + type: string + type: object handler.CreateSubscription.body: properties: channel: @@ -440,10 +445,12 @@ definitions: type: boolean messages_sent: type: integer + quota_max: + type: integer + quota_remaining: + type: integer quota_used: type: integer - quota_used_day: - type: string read_key: type: string send_key: @@ -473,10 +480,12 @@ definitions: type: boolean messages_sent: type: integer + quota_max: + type: integer + quota_remaining: + type: integer quota_used: type: integer - quota_used_day: - type: string read_key: type: string send_key: @@ -1322,6 +1331,44 @@ paths: summary: List channels of a user (subscribed/owned) tags: - API-v2 + /api/users/{uid}/channels/: + post: + operationId: api-channels-create + parameters: + - description: UserID + in: path + name: uid + required: true + type: integer + - description: ' ' + in: body + name: post_body + schema: + $ref: '#/definitions/handler.CreateChannel.body' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/models.ChannelJSON' + "400": + description: supplied values/parameters cannot be parsed / are invalid + schema: + $ref: '#/definitions/ginresp.apiError' + "401": + description: user is not authorized / has missing permissions + schema: + $ref: '#/definitions/ginresp.apiError' + "409": + description: channel already exists + schema: + $ref: '#/definitions/ginresp.apiError' + "500": + description: internal server error + schema: + $ref: '#/definitions/ginresp.apiError' + summary: Create a new (empty) channel + tags: + - API-v2 /api/users/{uid}/channels/{cid}: get: operationId: api-channels-get diff --git a/server/test/channel_test.go b/server/test/channel_test.go index 0aa30e7..0b0cc83 100644 --- a/server/test/channel_test.go +++ b/server/test/channel_test.go @@ -137,4 +137,28 @@ func TestChannelNameNormalization(t *testing.T) { } } +func TestListChannels(t *testing.T) { + t.SkipNow() //TODO +} + +func TestListChannelsOwned(t *testing.T) { + t.SkipNow() //TODO +} + +func TestListChannelsSubscribedAny(t *testing.T) { + t.SkipNow() //TODO +} + +func TestListChannelsAllAny(t *testing.T) { + t.SkipNow() //TODO +} + +func TestListChannelsSubscribed(t *testing.T) { + t.SkipNow() //TODO +} + +func TestListChannelsAll(t *testing.T) { + t.SkipNow() //TODO +} + //TODO test missing channel-xx methods diff --git a/server/test/message_test.go b/server/test/message_test.go index 29490cc..60f0745 100644 --- a/server/test/message_test.go +++ b/server/test/message_test.go @@ -35,7 +35,7 @@ func TestSearchMessageFTSMulti(t *testing.T) { //TODO list messages by chan_key -//TODO list messages from channel that you cannot see +//TODO (fail to) list messages from channel that you cannot see func TestDeleteMessage(t *testing.T) { _, baseUrl, stop := tt.StartSimpleWebserver(t) diff --git a/server/test/user_test.go b/server/test/user_test.go index 016bdf3..682d4f4 100644 --- a/server/test/user_test.go +++ b/server/test/user_test.go @@ -215,4 +215,48 @@ func TestDeleteUser(t *testing.T) { } -//TODO test user /w pro-token +func TestCreateProUser(t *testing.T) { + _, baseUrl, stop := tt.StartSimpleWebserver(t) + defer stop() + + { + r0 := tt.RequestPost[gin.H](t, baseUrl, "/api/users", gin.H{ + "no_client": true, + }) + + tt.AssertEqual(t, "is_pro", false, r0["is_pro"]) + } + + { + r1 := tt.RequestPost[gin.H](t, baseUrl, "/api/users", gin.H{ + "no_client": true, + "pro_token": "ANDROID|v2|PURCHASED:000", + }) + + tt.AssertEqual(t, "is_pro", true, r1["is_pro"]) + } + + { + r2 := tt.RequestPost[gin.H](t, baseUrl, "/api/users", gin.H{ + "agent_model": "DUMMY_PHONE", + "agent_version": "4X", + "client_type": "ANDROID", + "fcm_token": "DUMMY_FCM", + }) + + tt.AssertEqual(t, "is_pro", false, r2["is_pro"]) + } + + { + r3 := tt.RequestPost[gin.H](t, baseUrl, "/api/users", gin.H{ + "agent_model": "DUMMY_PHONE", + "agent_version": "4X", + "client_type": "ANDROID", + "fcm_token": "DUMMY_FCM", + "pro_token": "ANDROID|v2|PURCHASED:000", + }) + + tt.AssertEqual(t, "is_pro", true, r3["is_pro"]) + } + +}