From 3fcd6221d2a0a66e8b7b5237919d270f8ab8f9e0 Mon Sep 17 00:00:00 2001 From: Bernhard B Date: Sun, 20 Mar 2022 20:39:40 +0100 Subject: [PATCH] added new REST API endpoints * added endpoint to add members to an existing group * added endpoint to remove members from an existing group see #210 --- src/api/api.go | 92 +++++++++++++++++++++++++++++++++++++ src/client/client.go | 58 ++++++++++++++++++++++++ src/docs/docs.go | 103 ++++++++++++++++++++++++++++++++++++++++++ src/docs/swagger.json | 103 ++++++++++++++++++++++++++++++++++++++++++ src/docs/swagger.yaml | 68 ++++++++++++++++++++++++++++ src/main.go | 2 + 6 files changed, 426 insertions(+) diff --git a/src/api/api.go b/src/api/api.go index fea4f0e..ad16b1e 100644 --- a/src/api/api.go +++ b/src/api/api.go @@ -47,6 +47,10 @@ type CreateGroupRequest struct { GroupLinkState string `json:"group_link" enums:"disabled,enabled,enabled-with-approval"` } +type ChangeGroupMembersRequest struct { + Members []string `json:"members"` +} + type LoggingConfiguration struct { Level string `json:"Level"` } @@ -510,6 +514,94 @@ func (a *Api) CreateGroup(c *gin.Context) { c.JSON(201, CreateGroupResponse{Id: groupId}) } +// @Summary Add one or more members to an existing Signal Group. +// @Tags Groups +// @Description Add one or more members to an existing Signal Group. +// @Accept json +// @Produce json +// @Success 204 {string} OK +// @Failure 400 {object} Error +// @Param data body ChangeGroupMembersRequest true "Members" +// @Param number path string true "Registered Phone Number" +// @Router /v1/groups/{number}/{groupid}/members [post] +func (a *Api) AddMembersToGroup(c *gin.Context) { + number := c.Param("number") + if number == "" { + c.JSON(400, Error{Msg: "Couldn't process request - number missing"}) + return + } + + groupId := c.Param("groupid") + if groupId == "" { + c.JSON(400, Error{Msg: "Couldn't process request - group id missing"}) + return + } + + var req ChangeGroupMembersRequest + err := c.BindJSON(&req) + if err != nil { + c.JSON(400, Error{Msg: "Couldn't process request - invalid request"}) + return + } + + err = a.signalClient.AddMembersToGroup(number, groupId, req.Members) + if err != nil { + switch err.(type) { + case *client.NotFoundError: + c.JSON(404, Error{Msg: err.Error()}) + return + default: + c.JSON(400, Error{Msg: err.Error()}) + return + } + } + c.Status(http.StatusNoContent) +} + +// @Summary Remove one or more members from an existing Signal Group. +// @Tags Groups +// @Description Remove one or more members from an existing Signal Group. +// @Accept json +// @Produce json +// @Success 204 {string} OK +// @Failure 400 {object} Error +// @Param data body ChangeGroupMembersRequest true "Members" +// @Param number path string true "Registered Phone Number" +// @Router /v1/groups/{number}/{groupid}/members [delete] +func (a *Api) RemoveMembersFromGroup(c *gin.Context) { + number := c.Param("number") + if number == "" { + c.JSON(400, Error{Msg: "Couldn't process request - number missing"}) + return + } + + groupId := c.Param("groupid") + if groupId == "" { + c.JSON(400, Error{Msg: "Couldn't process request - group id missing"}) + return + } + + var req ChangeGroupMembersRequest + err := c.BindJSON(&req) + if err != nil { + c.JSON(400, Error{Msg: "Couldn't process request - invalid request"}) + return + } + + err = a.signalClient.RemoveMembersFromGroup(number, groupId, req.Members) + if err != nil { + switch err.(type) { + case *client.NotFoundError: + c.JSON(404, Error{Msg: err.Error()}) + return + default: + c.JSON(400, Error{Msg: err.Error()}) + return + } + } + c.Status(http.StatusNoContent) +} + // @Summary List all Signal Groups. // @Tags Groups // @Description List all Signal Groups. diff --git a/src/client/client.go b/src/client/client.go index 9a48b67..3b8a2a1 100644 --- a/src/client/client.go +++ b/src/client/client.go @@ -686,6 +686,64 @@ func (s *SignalClient) CreateGroup(number string, name string, members []string, return groupId, nil } +func (s *SignalClient) updateGroupMembers(number string, groupId string, members []string, add bool) error { + var err error + + if len(members) == 0 { + return nil + } + + group, err := s.GetGroup(number, groupId) + if err != nil { + return err + } + + if group == nil { + return &NotFoundError{Description: "No group with that group id found"} + } + + if s.signalCliMode == JsonRpc { + type Request struct { + Name string `json:"name,omitempty"` + Members []string `json:"member,omitempty"` + RemoveMembers []string `json:"remove-member,omitempty"` + GroupId string `json:"groupId"` + } + request := Request{GroupId: groupId} + if add { + request.Members = append(request.Members, members...) + } else { + request.RemoveMembers = append(request.RemoveMembers, members...) + } + + jsonRpc2Client, err := s.getJsonRpc2Client(number) + if err != nil { + return err + } + _, err = jsonRpc2Client.getRaw("updateGroup", request) + } else { + cmd := []string{"--config", s.signalCliConfig, "-a", number, "updateGroup"} + + if add { + cmd = append(cmd, "-m") + } else { + cmd = append(cmd, "-r") + } + cmd = append(cmd, members...) + + _, err = runSignalCli(true, cmd, "", s.signalCliMode) + } + return err +} + +func (s *SignalClient) AddMembersToGroup(number string, groupId string, members []string) error { + return s.updateGroupMembers(number, groupId, members, true) +} + +func (s *SignalClient) RemoveMembersFromGroup(number string, groupId string, members []string) error { + return s.updateGroupMembers(number, groupId, members, false) +} + func (s *SignalClient) GetGroups(number string) ([]GroupEntry, error) { groupEntries := []GroupEntry{} diff --git a/src/docs/docs.go b/src/docs/docs.go index fa2e4bd..62b45c5 100644 --- a/src/docs/docs.go +++ b/src/docs/docs.go @@ -557,6 +557,98 @@ var doc = `{ } } }, + "/v1/groups/{number}/{groupid}/members": { + "post": { + "description": "Add one or more members to an existing Signal Group.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Groups" + ], + "summary": "Add one or more members to an existing Signal Group.", + "parameters": [ + { + "description": "Members", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.ChangeGroupMembersRequest" + } + }, + { + "type": "string", + "description": "Registered Phone Number", + "name": "number", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.Error" + } + } + } + }, + "delete": { + "description": "Remove one or more members from an existing Signal Group.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Groups" + ], + "summary": "Remove one or more members from an existing Signal Group.", + "parameters": [ + { + "description": "Members", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.ChangeGroupMembersRequest" + } + }, + { + "type": "string", + "description": "Registered Phone Number", + "name": "number", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.Error" + } + } + } + } + }, "/v1/groups/{number}/{groupid}/quit": { "post": { "description": "Quit the specified Signal Group.", @@ -1266,6 +1358,17 @@ var doc = `{ } } }, + "api.ChangeGroupMembersRequest": { + "type": "object", + "properties": { + "members": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "api.Configuration": { "type": "object", "properties": { diff --git a/src/docs/swagger.json b/src/docs/swagger.json index fa3fba4..baa8ed2 100644 --- a/src/docs/swagger.json +++ b/src/docs/swagger.json @@ -541,6 +541,98 @@ } } }, + "/v1/groups/{number}/{groupid}/members": { + "post": { + "description": "Add one or more members to an existing Signal Group.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Groups" + ], + "summary": "Add one or more members to an existing Signal Group.", + "parameters": [ + { + "description": "Members", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.ChangeGroupMembersRequest" + } + }, + { + "type": "string", + "description": "Registered Phone Number", + "name": "number", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.Error" + } + } + } + }, + "delete": { + "description": "Remove one or more members from an existing Signal Group.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Groups" + ], + "summary": "Remove one or more members from an existing Signal Group.", + "parameters": [ + { + "description": "Members", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.ChangeGroupMembersRequest" + } + }, + { + "type": "string", + "description": "Registered Phone Number", + "name": "number", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content", + "schema": { + "type": "string" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/api.Error" + } + } + } + } + }, "/v1/groups/{number}/{groupid}/quit": { "post": { "description": "Quit the specified Signal Group.", @@ -1250,6 +1342,17 @@ } } }, + "api.ChangeGroupMembersRequest": { + "type": "object", + "properties": { + "members": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "api.Configuration": { "type": "object", "properties": { diff --git a/src/docs/swagger.yaml b/src/docs/swagger.yaml index 5fab35c..3eabee1 100644 --- a/src/docs/swagger.yaml +++ b/src/docs/swagger.yaml @@ -5,6 +5,13 @@ definitions: uri: type: string type: object + api.ChangeGroupMembersRequest: + properties: + members: + items: + type: string + type: array + type: object api.Configuration: properties: logging: @@ -567,6 +574,67 @@ paths: summary: Join a Signal Group. tags: - Groups + /v1/groups/{number}/{groupid}/members: + delete: + consumes: + - application/json + description: Remove one or more members from an existing Signal Group. + parameters: + - description: Members + in: body + name: data + required: true + schema: + $ref: '#/definitions/api.ChangeGroupMembersRequest' + - description: Registered Phone Number + in: path + name: number + required: true + type: string + produces: + - application/json + responses: + "204": + description: No Content + schema: + type: string + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.Error' + summary: Remove one or more members from an existing Signal Group. + tags: + - Groups + post: + consumes: + - application/json + description: Add one or more members to an existing Signal Group. + parameters: + - description: Members + in: body + name: data + required: true + schema: + $ref: '#/definitions/api.ChangeGroupMembersRequest' + - description: Registered Phone Number + in: path + name: number + required: true + type: string + produces: + - application/json + responses: + "204": + description: No Content + schema: + type: string + "400": + description: Bad Request + schema: + $ref: '#/definitions/api.Error' + summary: Add one or more members to an existing Signal Group. + tags: + - Groups /v1/groups/{number}/{groupid}/quit: post: consumes: diff --git a/src/main.go b/src/main.go index e88214a..fdb6a70 100644 --- a/src/main.go +++ b/src/main.go @@ -186,6 +186,8 @@ func main() { groups.POST(":number/:groupid/block", api.BlockGroup) groups.POST(":number/:groupid/join", api.JoinGroup) groups.POST(":number/:groupid/quit", api.QuitGroup) + groups.POST(":number/:groupid/members", api.AddMembersToGroup) + groups.DELETE(":number/:groupid/members", api.RemoveMembersFromGroup) } link := v1.Group("qrcodelink")