Skip to content

Commit 9bff898

Browse files
feat(collaboration): add UserExtraInfo with avatar and mail to CheckFileInfo
Populate the UserExtraInfo WOPI property in CheckFileInfo so Collabora Online can display user avatars in the collaborator list during co-editing sessions. Note: The avatar URL points to the Graph API photo endpoint, which is now accessible without authentication for GET requests (proxy route marked unprotected, graph auth middleware bypassed for photo GETs) otherwise I was getting auth popups. This follows the same common user pattern that users expect to. ```json { "avatar": "http://url/to/user/avatar", "mail": "user@server.com" } ``` https://sdk.collaboraonline.com/docs/advanced_integration.html#userextrainfo so, after this we get in checkfileinfo the email as part of UserExtraInfo: ```json { "BaseFileName": "Pedro-filled-hazcom.docx", "UserFriendlyName": "Admin", "UserId": "346364...39323030", "UserCanWrite": true, "UserCanRename": true, "IsAdminUser": true, "EnableInsertRemoteImage": true, "EnableInsertRemoteFile": true, "EnableOwnerTermination": true, "UserExtraInfo": { "avatar": "https://localhost:9200/graph/v1.0/users/4cd4ae16-11f0-408f-881e-a987da96d136/photo/$value", "mail": "admin@example.org" }, "PostMessageOrigin": "https://localhost:9200", "message": "CheckFileInfo: success" } I have ran: ``` go test ./services/collaboration/... ./services/graph/... ./services/proxy/... ``` all tests have passed. Signed-off-by: Pedro Pinto Silva <pedro.silva@collabora.com>
1 parent 0c8829c commit 9bff898

File tree

6 files changed

+42
-3
lines changed

6 files changed

+42
-3
lines changed

services/collaboration/pkg/connector/fileconnector.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,17 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse,
13021302
}
13031303
}
13041304

1305+
if !isPublicShare && !isAnonymousUser {
1306+
infoMap[fileinfo.KeyUserExtraInfo] = &fileinfo.UserExtraInfo{
1307+
Avatar: (&url.URL{
1308+
Scheme: ocURL.Scheme,
1309+
Host: ocURL.Host,
1310+
Path: path.Join(ocURL.Path, "graph/v1.0/users", user.GetId().GetOpaqueId(), "photo/$value"),
1311+
}).String(),
1312+
Mail: user.GetMail(),
1313+
}
1314+
}
1315+
13051316
// if the file content is empty and a template reference is set, add the template source URL
13061317
if wopiContext.TemplateReference != nil && statRes.GetInfo().GetSize() == 0 {
13071318
if tu, err := f.createDownloadURL(wopiContext, collaborationURL); err == nil {

services/collaboration/pkg/connector/fileconnector_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1994,6 +1994,10 @@ var _ = Describe("FileConnector", func() {
19941994
PostMessageOrigin: "https://cloud.opencloud.test",
19951995
EnableInsertRemoteImage: true,
19961996
IsAdminUser: true,
1997+
UserExtraInfo: &fileinfo.UserExtraInfo{
1998+
Avatar: "https://cloud.opencloud.test/graph/v1.0/users/aabbcc/photo/$value",
1999+
Mail: "shaft@example.com",
2000+
},
19972001
}
19982002

19992003
response, err := fc.CheckFileInfo(ctx)

services/collaboration/pkg/connector/fileinfo/collabora.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
package fileinfo
22

3+
// UserExtraInfo contains additional user info shared across collaborative
4+
// editing views, such as the user's avatar image and email.
5+
// https://sdk.collaboraonline.com/docs/advanced_integration.html#userextrainfo
6+
type UserExtraInfo struct {
7+
Avatar string `json:"avatar,omitempty"`
8+
Mail string `json:"mail,omitempty"`
9+
}
10+
311
// Collabora fileInfo properties
412
//
513
// Collabora WOPI check file info specification:
@@ -62,7 +70,8 @@ type Collabora struct {
6270
IsAnonymousUser bool `json:"IsAnonymousUser,omitempty"`
6371

6472
// JSON object that contains additional info about the user, namely the avatar image.
65-
//UserExtraInfo -> requires definition, currently not used
73+
// Shared among all views in collaborative editing sessions.
74+
UserExtraInfo *UserExtraInfo `json:"UserExtraInfo,omitempty"`
6675
// JSON object that contains additional info about the user, but unlike the UserExtraInfo it is not shared among the views in collaborative editing sessions.
6776
//UserPrivateInfo -> requires definition, currently not used
6877

@@ -131,7 +140,8 @@ func (cinfo *Collabora) SetProperties(props map[string]interface{}) {
131140
cinfo.SaveAsPostmessage = value.(bool)
132141
case KeyEnableOwnerTermination:
133142
cinfo.EnableOwnerTermination = value.(bool)
134-
//UserExtraInfo -> requires definition, currently not used
143+
case KeyUserExtraInfo:
144+
cinfo.UserExtraInfo = value.(*UserExtraInfo)
135145
//UserPrivateInfo -> requires definition, currently not used
136146
case KeyWatermarkText:
137147
cinfo.WatermarkText = value.(string)

services/collaboration/pkg/connector/fileinfo/fileinfo.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ const (
113113
KeyDownloadAsPostMessage = "DownloadAsPostMessage"
114114
KeySaveAsPostmessage = "SaveAsPostmessage"
115115
KeyEnableOwnerTermination = "EnableOwnerTermination"
116-
//KeyUserExtraInfo -> requires definition, currently not used
116+
KeyUserExtraInfo = "UserExtraInfo"
117117
//KeyUserPrivateInfo -> requires definition, currently not used
118118
KeyWatermarkText = "WatermarkText"
119119

services/graph/pkg/middleware/auth.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package middleware
22

33
import (
44
"net/http"
5+
"strings"
56

67
gmmetadata "go-micro.dev/v4/metadata"
78
"google.golang.org/grpc/metadata"
@@ -41,6 +42,12 @@ func Auth(opts ...account.Option) func(http.Handler) http.Handler {
4142
}
4243
return func(next http.Handler) http.Handler {
4344
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
45+
// Allow unauthenticated GET access to user profile photos (avatars).
46+
if r.Method == http.MethodGet && strings.Contains(r.URL.Path, "/users/") && strings.HasSuffix(r.URL.Path, "/photo/$value") {
47+
next.ServeHTTP(w, r)
48+
return
49+
}
50+
4451
ctx := r.Context()
4552
t := r.Header.Get(revactx.TokenHeader)
4653
if t == "" {

services/proxy/pkg/config/defaults/defaultconfig.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,13 @@ func DefaultPolicies() []config.Policy {
273273
Endpoint: "/graph/v1.0/invitations",
274274
Service: "eu.opencloud.web.invitations",
275275
},
276+
{
277+
Type: config.RegexRoute,
278+
Method: "GET",
279+
Endpoint: `/graph/v1\.0/users/[^/]+/photo/\$value`,
280+
Service: "eu.opencloud.web.graph",
281+
Unprotected: true,
282+
},
276283
{
277284
Endpoint: "/graph/",
278285
Service: "eu.opencloud.web.graph",

0 commit comments

Comments
 (0)