added new endpoint to return a group's avatar

This commit is contained in:
Bernhard B 2025-06-03 22:18:29 +02:00
parent 59207541c1
commit b3a6ee1e5d
6 changed files with 214 additions and 0 deletions

View File

@ -967,6 +967,40 @@ func (a *Api) GetGroup(c *gin.Context) {
}
}
// @Summary Returns the avatar of a Signal Group.
// @Tags Groups
// @Description Returns the avatar of a Signal Group.
// @Accept json
// @Produce json
// @Success 200 {string} string "Image"
// @Failure 400 {object} Error
// @Param number path string true "Registered Phone Number"
// @Param groupid path string true "Group ID"
// @Router /v1/groups/{number}/{groupid}/avatar [get]
func (a *Api) GetGroupAvatar(c *gin.Context) {
number, err := url.PathUnescape(c.Param("number"))
if err != nil {
c.JSON(400, Error{Msg: "Couldn't process request - malformed number"})
return
}
groupId := c.Param("groupid")
groupAvatar, err := a.signalClient.GetGroupAvatar(number, groupId)
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
}
}
mimeType := mimetype.Detect(groupAvatar)
c.Data(200, mimeType.String(), groupAvatar)
}
// @Summary Delete a Signal Group.
// @Tags Groups
// @Description Delete the specified Signal Group.

View File

@ -1288,6 +1288,57 @@ func (s *SignalClient) GetGroup(number string, groupId string) (*GroupEntry, err
return nil, nil
}
func (s *SignalClient) GetGroupAvatar(number string, groupId string) ([]byte, error) {
var err error
var rawData string
internalGroupId, err := ConvertGroupIdToInternalGroupId(groupId)
if err != nil {
return []byte{}, errors.New("Invalid group id")
}
if s.signalCliMode == JsonRpc {
type Request struct {
GroupId string `json:"groupId"`
}
request := Request{GroupId: internalGroupId}
jsonRpc2Client, err := s.getJsonRpc2Client()
if err != nil {
return []byte{}, err
}
rawData, err = jsonRpc2Client.getRaw("getAvatar", &number, request)
if err != nil {
if err.Error() == "Could not find avatar" {
return []byte{},&NotFoundError{Description: "No avatar found."}
}
return []byte{}, err
}
} else {
rawData, err = s.cliClient.Execute(true, []string{"--config", s.signalCliConfig, "-o", "json", "-a", number, "getAvatar", "-g", internalGroupId}, "")
if err != nil {
return []byte{}, err
}
}
type SignalCliResponse struct {
Data string `json:"data"`
}
var signalCliResponse SignalCliResponse
err = json.Unmarshal([]byte(rawData), &signalCliResponse)
if err != nil {
return []byte{}, errors.New("Couldn't unmarshal data: " + err.Error())
}
groupAvatarBytes, err := base64.StdEncoding.DecodeString(signalCliResponse.Data)
if err != nil {
return []byte{}, errors.New("Couldn't decode base64 encoded group avatar: " + err.Error())
}
return groupAvatarBytes, nil
}
func (s *SignalClient) DeleteGroup(number string, groupId string) error {
if s.signalCliMode == JsonRpc {
type Request struct {

View File

@ -1080,6 +1080,51 @@ const docTemplate = `{
}
}
},
"/v1/groups/{number}/{groupid}/avatar": {
"get": {
"description": "Returns the avatar of a Signal Group.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Groups"
],
"summary": "Returns the avatar of a Signal Group.",
"parameters": [
{
"type": "string",
"description": "Registered Phone Number",
"name": "number",
"in": "path",
"required": true
},
{
"type": "string",
"description": "Group ID",
"name": "groupid",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "Image",
"schema": {
"type": "string"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/api.Error"
}
}
}
}
},
"/v1/groups/{number}/{groupid}/block": {
"post": {
"description": "Block the specified Signal Group.",
@ -2720,6 +2765,9 @@ const docTemplate = `{
},
"status": {
"type": "string"
},
"uuid": {
"type": "string"
}
}
},

View File

@ -1077,6 +1077,51 @@
}
}
},
"/v1/groups/{number}/{groupid}/avatar": {
"get": {
"description": "Returns the avatar of a Signal Group.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Groups"
],
"summary": "Returns the avatar of a Signal Group.",
"parameters": [
{
"type": "string",
"description": "Registered Phone Number",
"name": "number",
"in": "path",
"required": true
},
{
"type": "string",
"description": "Group ID",
"name": "groupid",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "Image",
"schema": {
"type": "string"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/api.Error"
}
}
}
}
},
"/v1/groups/{number}/{groupid}/block": {
"post": {
"description": "Block the specified Signal Group.",
@ -2717,6 +2762,9 @@
},
"status": {
"type": "string"
},
"uuid": {
"type": "string"
}
}
},

View File

@ -367,6 +367,8 @@ definitions:
type: string
status:
type: string
uuid:
type: string
type: object
client.ListContactsResponse:
properties:
@ -1178,6 +1180,36 @@ paths:
summary: Add one or more admins to an existing Signal Group.
tags:
- Groups
/v1/groups/{number}/{groupid}/avatar:
get:
consumes:
- application/json
description: Returns the avatar of a Signal Group.
parameters:
- description: Registered Phone Number
in: path
name: number
required: true
type: string
- description: Group ID
in: path
name: groupid
required: true
type: string
produces:
- application/json
responses:
"200":
description: Image
schema:
type: string
"400":
description: Bad Request
schema:
$ref: '#/definitions/api.Error'
summary: Returns the avatar of a Signal Group.
tags:
- Groups
/v1/groups/{number}/{groupid}/block:
post:
consumes:

View File

@ -210,6 +210,7 @@ func main() {
groups.POST(":number", api.CreateGroup)
groups.GET(":number", api.GetGroups)
groups.GET(":number/:groupid", api.GetGroup)
groups.GET(":number/:groupid/avatar", api.GetGroupAvatar)
groups.DELETE(":number/:groupid", api.DeleteGroup)
groups.POST(":number/:groupid/block", api.BlockGroup)
groups.POST(":number/:groupid/join", api.JoinGroup)